diff --git a/src/Ultra.Sampler/MacOS/NativeModuleEvent.cs b/src/Ultra.Sampler/MacOS/NativeModuleEvent.cs
index 7d1ec21..cf62a25 100644
--- a/src/Ultra.Sampler/MacOS/NativeModuleEvent.cs
+++ b/src/Ultra.Sampler/MacOS/NativeModuleEvent.cs
@@ -2,6 +2,8 @@
// Licensed under the BSD-Clause 2 license.
// See license.txt file in the project root for full license information.
+using System.Text;
+
namespace Ultra.Sampler.MacOS;
internal struct NativeModuleEvent
@@ -13,6 +15,6 @@ internal struct NativeModuleEvent
public override string ToString()
{
- return $"{nameof(LoadAddress)}: 0x{LoadAddress:X8}, {nameof(Path)}: {Path}, {nameof(TimestampUtc)}: {TimestampUtc:O}";
+ return $"{nameof(LoadAddress)}: 0x{LoadAddress:X8}, {nameof(Path)}: {Encoding.UTF8.GetString(Path ?? [])}, {nameof(TimestampUtc)}: {TimestampUtc:O}";
}
}
\ No newline at end of file
diff --git a/src/Ultra.Sampler/Ultra.Sampler.csproj b/src/Ultra.Sampler/Ultra.Sampler.csproj
index 7fb9d57..18a3280 100644
--- a/src/Ultra.Sampler/Ultra.Sampler.csproj
+++ b/src/Ultra.Sampler/Ultra.Sampler.csproj
@@ -6,6 +6,11 @@
enable
true
false
+ true
+ libUltraSampler
+ true
+ <_SuppressNativeLibEventSourceWarning>true
+ true
diff --git a/src/Ultra.Sampler/build_native.sh b/src/Ultra.Sampler/build_native.sh
new file mode 100755
index 0000000..ccde0be
--- /dev/null
+++ b/src/Ultra.Sampler/build_native.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env sh
+dotnet publish -c Release -r osx-arm64
+LIB_NAME=libUltraSampler.dylib
+LIB_OUTPUT_PATH=./bin/Release/net8.0/osx-arm64/publish/$LIB_NAME
+install_name_tool -id $LIB_NAME $LIB_OUTPUT_PATH
+cp $LIB_OUTPUT_PATH ./$LIB_NAME
+clang -shared -O2 -o libUltraSamplerIndirect.dyld ultra_sampler_indirect.cpp ./$LIB_NAME
diff --git a/src/Ultra.Sampler/ultra_sampler_indirect.cpp b/src/Ultra.Sampler/ultra_sampler_indirect.cpp
new file mode 100644
index 0000000..8f12523
--- /dev/null
+++ b/src/Ultra.Sampler/ultra_sampler_indirect.cpp
@@ -0,0 +1,66 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern "C" {
+ void ultra_sampler_start();
+
+
+ void set_temporary_tmpdir(const char* sub_dir_name, void (*func)()) {
+ // Get the current TMPDIR
+ const char* original_tmpdir = getenv("TMPDIR");
+ if (!original_tmpdir) {
+ return;
+ }
+
+ size_t original_tmpdir_len = strlen(original_tmpdir);
+ bool has_trailing_slash = original_tmpdir[original_tmpdir_len - 1] == '/';
+
+ // Construct the new TMPDIR path
+ size_t new_tmpdir_len = original_tmpdir_len + strlen(sub_dir_name) + 1 + (has_trailing_slash ? 1 : 0); // +1 for '\0', and +1 for the trailing slash
+ char* new_tmpdir = (char*)malloc(new_tmpdir_len);
+ if (!new_tmpdir) {
+ // perror("Failed to allocate memory");
+ return;
+ }
+
+ snprintf(new_tmpdir, new_tmpdir_len, has_trailing_slash ? "%s%s/" : "%s/%s/", original_tmpdir, sub_dir_name);
+
+ // Create the subdirectory if it doesn't exist
+ if (mkdir(new_tmpdir, 0700) != 0 && errno != EEXIST) {
+ //perror("Failed to create directory");
+ free(new_tmpdir);
+ return;
+ }
+
+ // Set the TMPDIR environment variable to the new subdirectory
+ if (setenv("TMPDIR", new_tmpdir, 1) != 0) {
+ //perror("Failed to set TMPDIR");
+ free(new_tmpdir);
+ return;
+ }
+ free(new_tmpdir);
+
+ pid_t pid = getpid();
+ printf("Current Process pid: %d tmpdir: %s\n", pid, getenv("TMPDIR"));
+
+ // Call the arbitrary function
+ func();
+
+ // Restore the original TMPDIR
+ setenv("TMPDIR", original_tmpdir, 1);
+ }
+
+ __attribute__((visibility("default"),used))
+ void ultra_sampler_boot()
+ {
+ set_temporary_tmpdir(".ultra", ultra_sampler_start);
+ }
+
+ __attribute__((visibility("default"),used))
+ __attribute__((section("__DATA,__mod_init_func"))) void (*ultra_sampler_boot_ptr)() = &ultra_sampler_boot;
+}