2

What should the syntax be to call the MacOS' os_log from C# in a .NET Core console app?

Based on
https://developer.apple.com/documentation/os/os_log
and
How to use iOS OSLog with Xamarin?
and
https://opensource.apple.com/source/xnu/xnu-4903.221.2/libkern/os/log.h.auto.html
I was expecting something like this:

using System.Runtime.InteropServices;

namespace Foo 
{
 class Program
 {
  [DllImport("__Internal", EntryPoint = "os_log_create")]
  private static extern IntPtr os_log_create(string subsystem, string category);

  [DllImport("__Internal", EntryPoint = "os_log")]
  private static extern void os_log(IntPtr log, string format, string message);

  static void Main(string[] args)
  {  
   IntPtr log = os_log_create("some.bundle.id", "SomeCategory");
   os_log(log, "%s", "Test!");
  }
 }
}

However, when I try to run this on my Mac I get a System.DllNotFoundException that says Unable to load shared library '__Internal' or one of its dependencies... .

Any help with this issue or P/Invoke between C# and MacOS would be very helpful, thanks!

4

1 回答 1

8

Macro os_log

In contrast to the os_log_create function, os_log is a macro, as already mentioned in the comments.

So if you would write in C:

os_log(log, "%{public}s", "Test!");

It would finally call a function named _os_log_impl, but the first parameter of that would be a pointer __dso_handle to which we don't have access from the managed side.

Possible Solution

But you don't have to do without the new logging system from Apple. One possibility is to create a dynamic library that provides a defined API that can easily be called from the managed C# code.

How to Create a Dynamic Library in Xcode

It is easy to create a dynamic library in Xcode:

  • choose in XCode <File/New Project>

  • choose Library template in the macOS section

  • use Type Dynamic

Minimal Example

A minimal .c example for our own Logging library might look like this:

 #include <os/log.h>

 extern void Log(os_log_t log, char *message) {
     os_log(log, "%{public}s", message);
 }

Calling from .Net

I took your source and only slightly modified it:

using System;
using System.Runtime.InteropServices;

namespace Foo 
{
    class Program
    {
        [DllImport("System", EntryPoint = "os_log_create")]
        private static extern IntPtr os_log_create(string subsystem, string category);

        [DllImport("Logging", EntryPoint = "Log")]
        private static extern void Log(IntPtr log, string msg);

        static void Main(string[] args)
        {  
            IntPtr log = os_log_create("some.bundle.id", "SomeCategory");
            Log(log, "Test!");
        }
    }
}

The dynamic library created with Xcode has the name Logging. Our in C created logging function is named Log here.

Of course you can design the API as comfortable as you want, this should be a minimal example that is as close to the question as possible.

Output in Console Utility

The output in the Console utility (if you filter for some.bundle.id) would look like this:

output in Console utility

于 2018-12-15T17:25:26.720 回答