// onnxruntime, loaded at run time. Nothing is linked: ort_load finds the library, takes its one // export, OrtGetApiBase, and from it the OrtApi function table (bindings.jai, from generate.jai). // A program that imports this module starts without onnxruntime and only fails in ort_load. // // Version: see fetch.jai (ORT_VERSION) and /VERSION.txt. The bindings are for ORT_API_VERSION; // an older library is refused, a newer one serves this version of the table. ort: struct { api: *OrtApi; library_path: string; // the library that was loaded version: string; // onnxruntime's own version string, such as 1.30.0 // What the engines' environments log, to the console: set before the first engine is made, as // onnxruntime keeps one environment per process. INFO shows each GPU arena extension and its size. log_level := OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING; } // Loads onnxruntime from the first folder that has it: beside the running executable, then each // of folders. A full path is always used: Windows keeps an older onnxruntime.dll in System32 for // its own use, which a bare name could find first. ort_load :: (folders: [] string = .[]) -> ok: bool, error: string { if ort.api return true, ""; candidates: [..] string; candidates.allocator = temp; array_add(*candidates, path_strip_filename(get_path_of_running_executable())); for folders array_add(*candidates, it); tried: [..] string; tried.allocator = temp; for folder: candidates { path := tprint("%/%", trim_right(folder, "/\\"), ORT_LIBRARY_NAME); if !file_exists(path) { array_add(*tried, path); continue; } get_api_base, load_error := ort_open_library(path); if !get_api_base return false, load_error; base := get_api_base(); if !base return false, tprint("% returned no API.", path); version := to_string(base.GetVersionString()); api := base.GetApi(ORT_API_VERSION); if !api return false, tprint("% is onnxruntime %, which does not offer API version % (these bindings); use the version fetch.jai pins.", path, version, ORT_API_VERSION); ort.api = api; ort.library_path = copy_string(path,, context.default_allocator); ort.version = copy_string(version,, context.default_allocator); return true, ""; } return false, tprint("% was not found. Looked for:\n %\nRun `jai fetch.jai` in modules/onnxruntime and rebuild, so the build copies it beside the executable.", ORT_LIBRARY_NAME, join(..tried, "\n ",, temp)); } // A failed status as its message, and the status released. ok and "" for success (a null status). ort_check :: (status: OrtStatusPtr) -> ok: bool, message: string { if !status return true, ""; message := tprint("%", to_string(ort.api.GetErrorMessage(status))); ort.api.ReleaseStatus(status); return false, message; } // A path as the C API takes it: UTF-16 on Windows, UTF-8 elsewhere. The bindings were generated on // Windows, where ORTCHAR_T is a wchar_t, so elsewhere the pointer is cast to the type they expect. Temp. ort_path :: (path: string) -> *ORTCHAR_T { #if OS == .WINDOWS { return utf8_to_wide(path,, temp); } else { return cast(*ORTCHAR_T) temp_c_string(path); } } #load "bindings.jai"; #load "session.jai"; #load "cuda.jai"; #scope_module Get_Api_Base :: #type () -> *OrtApiBase #c_call; #if OS == .WINDOWS { ORT_LIBRARY_NAME :: "onnxruntime.dll"; ort_open_library :: (path: string) -> Get_Api_Base, error: string { // Altered search path: the libraries onnxruntime loads in turn (onnxruntime_providers_shared.dll, // onnxruntime_providers_cuda.dll) are looked for in its folder. windows_path := replace(path, "/", "\\",, temp); module := LoadLibraryExW(utf8_to_wide(windows_path,, temp), null, LOAD_WITH_ALTERED_SEARCH_PATH); if !module return null, tprint("Could not load % (Windows error %).", path, GetLastError()); get_api_base := cast(Get_Api_Base) GetProcAddress(module, "OrtGetApiBase"); if !get_api_base return null, tprint("% has no OrtGetApiBase; it is not onnxruntime.", path); return get_api_base, ""; } #import "Windows"; #import "Windows_Utf8"; } else { #if OS == .MACOS ORT_LIBRARY_NAME :: "libonnxruntime.dylib"; else ORT_LIBRARY_NAME :: "libonnxruntime.so"; ort_open_library :: (path: string) -> Get_Api_Base, error: string { handle := dlopen(temp_c_string(path), RTLD_NOW); if !handle return null, tprint("Could not load %: %", path, to_string(dlerror())); get_api_base := cast(Get_Api_Base) dlsym(handle, "OrtGetApiBase"); if !get_api_base return null, tprint("% has no OrtGetApiBase; it is not onnxruntime.", path); return get_api_base, ""; } #import "POSIX"; } #import "Basic"; #import "String"; #import "File"; #import "File_Utilities"; #import "System"; #import "Sort"; #import "Atomics";