Skip to content

Commit

Permalink
Add libkmod
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Jul 19, 2024
1 parent 2f74d61 commit 3cf3a49
Show file tree
Hide file tree
Showing 18 changed files with 1,214 additions and 79 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/ci_build_libkmod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: ci_build_libkmod

on:
push:
branches:
- '**'
tags-ignore:
- '**'
paths:
- 'src/*.props'
- 'src/libkmod/**'
pull_request:

jobs:
build:
runs-on: 'ubuntu-latest'
steps:
#GITHUB_ACTION_PRE_STEP
- name: "Build, Test and Pack libkmod"
uses: xoofx/.github/.github/actions/dotnet-releaser-action@main
with:
dotnet-releaser-path: 'src/libkmod/dotnet-releaser.toml'
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
#GITHUB_ACTION_POST_STEP
22 changes: 22 additions & 0 deletions .github/workflows/ci_publish_libkmod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: ci_publish_libkmod

on:
push:
tags:
- "libkmod/*"
paths:
- 'src/*.props'
- 'src/libkmod/**'
pull_request:

jobs:
build:
runs-on: 'ubuntu-latest'
steps:
#GITHUB_ACTION_PRE_STEP
- name: "Build, Test and Publish libkmod"
uses: xoofx/.github/.github/actions/dotnet-releaser-action@main
with:
dotnet-releaser-path: 'src/libkmod/dotnet-releaser.toml'
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
#GITHUB_ACTION_POST_STEP
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ The following libraries are available:
| [XenoAtom.Interop.libdrm](src/libdrm)<br>libdrm is a userspace library that provides a user-space API to the Direct Rendering Manager. | [libdrm](https://gitlab.freedesktop.org/mesa/drm)<br>`2.4.120` | `linux` | [![Build Status](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libdrm.yml/badge.svg)](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libdrm.yml)<br>[![NuGet](https://img.shields.io/nuget/v/XenoAtom.Interop.libdrm.svg)](https://www.nuget.org/packages/XenoAtom.Interop.libdrm) |
| [XenoAtom.Interop.libgbm](src/libgbm)<br>libgbm is a userspace library that provides an abstraction for buffer management used by graphics drivers. | [libgbm](https://gitlab.freedesktop.org/mesa/mesa)<br>`24.0.9` | `linux` | [![Build Status](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libgbm.yml/badge.svg)](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libgbm.yml)<br>[![NuGet](https://img.shields.io/nuget/v/XenoAtom.Interop.libgbm.svg)](https://www.nuget.org/packages/XenoAtom.Interop.libgbm) |
| [XenoAtom.Interop.libshaderc](src/libshaderc)<br>libshaderc is a library for compiling GLSL/HLSL to SPIR-V. | [libshaderc](https://github.com/google/shaderc)<br>`2024.0` | `all` | [![Build Status](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libshaderc.yml/badge.svg)](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libshaderc.yml)<br>[![NuGet](https://img.shields.io/nuget/v/XenoAtom.Interop.libshaderc.svg)](https://www.nuget.org/packages/XenoAtom.Interop.libshaderc) |
| [XenoAtom.Interop.libkmod](src/libkmod)<br>libkmod is a library for managing kernel modules. | [libkmod](https://github.com/kmod-project/kmod/)<br>`32` | `linux` | [![Build Status](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libkmod.yml/badge.svg)](https://github.com/XenoAtom/XenoAtom.Interop/actions/workflows/ci_build_libkmod.yml)<br>[![NuGet](https://img.shields.io/nuget/v/XenoAtom.Interop.libkmod.svg)](https://www.nuget.org/packages/XenoAtom.Interop.libkmod) |

<!-- XENOATOM_INTEROP END - DO NOT EDIT --->

Expand Down
17 changes: 17 additions & 0 deletions src/XenoAtom.Interop.sln
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XenoAtom.Interop.libshaderc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XenoAtom.Interop.libshaderc.Tests", "libshaderc\XenoAtom.Interop.libshaderc.Tests\XenoAtom.Interop.libshaderc.Tests.csproj", "{76422969-B89F-4EBE-AB76-E51917A8EA9A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libkmod", "libkmod", "{6BE6E4E3-1EC2-4DA4-B99A-B4B198C40AEE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XenoAtom.Interop.libkmod", "libkmod\XenoAtom.Interop.libkmod\XenoAtom.Interop.libkmod.csproj", "{B2FC2BAB-934C-4E90-8C7D-1A928184D19E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XenoAtom.Interop.libkmod.Tests", "libkmod\XenoAtom.Interop.libkmod.Tests\XenoAtom.Interop.libkmod.Tests.csproj", "{A36B60C1-6326-44EA-B01D-DDCCBC3DA640}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -194,6 +200,14 @@ Global
{76422969-B89F-4EBE-AB76-E51917A8EA9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76422969-B89F-4EBE-AB76-E51917A8EA9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76422969-B89F-4EBE-AB76-E51917A8EA9A}.Release|Any CPU.Build.0 = Release|Any CPU
{B2FC2BAB-934C-4E90-8C7D-1A928184D19E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2FC2BAB-934C-4E90-8C7D-1A928184D19E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2FC2BAB-934C-4E90-8C7D-1A928184D19E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2FC2BAB-934C-4E90-8C7D-1A928184D19E}.Release|Any CPU.Build.0 = Release|Any CPU
{A36B60C1-6326-44EA-B01D-DDCCBC3DA640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A36B60C1-6326-44EA-B01D-DDCCBC3DA640}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A36B60C1-6326-44EA-B01D-DDCCBC3DA640}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A36B60C1-6326-44EA-B01D-DDCCBC3DA640}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -227,6 +241,9 @@ Global
{0742D969-0B9F-4034-BFC4-7B0C5B2FDFB7} = {DA3698BE-1790-4569-A569-ECA2F29E25A9}
{D4EA7E38-0C3F-48BA-9188-A925B4E8ABE2} = {0742D969-0B9F-4034-BFC4-7B0C5B2FDFB7}
{76422969-B89F-4EBE-AB76-E51917A8EA9A} = {0742D969-0B9F-4034-BFC4-7B0C5B2FDFB7}
{6BE6E4E3-1EC2-4DA4-B99A-B4B198C40AEE} = {DA3698BE-1790-4569-A569-ECA2F29E25A9}
{B2FC2BAB-934C-4E90-8C7D-1A928184D19E} = {6BE6E4E3-1EC2-4DA4-B99A-B4B198C40AEE}
{A36B60C1-6326-44EA-B01D-DDCCBC3DA640} = {6BE6E4E3-1EC2-4DA4-B99A-B4B198C40AEE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {95E8F3B3-49E8-400E-97A1-38D8B946DFCA}
Expand Down
75 changes: 75 additions & 0 deletions src/codegen/XenoAtom.Interop.CodeGen/GeneratorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
Expand Down Expand Up @@ -397,6 +398,80 @@ protected virtual IEnumerable<CppFunction> GetAdditionalExportedCppFunctions()
return Enumerable.Empty<CppFunction>();
}

protected static void ProcessConstStringArguments(CSharpMethod csMethod)
{
// If we have a potential marshalling for return/parameter string, we will duplicate the method with string marshalling
CSharpMethod? newManagedMethod = null;
for (var i = 0; i < csMethod.Parameters.Count; i++)
{
var param = csMethod.Parameters[i];
var cppType = (CppType)param.ParameterType!.CppElement!;
if (cppType.TryGetElementTypeFromPointer(out var isConst, out var elementType) && isConst)
{
if (elementType is CppPrimitiveType { Kind: CppPrimitiveKind.Char })
{
newManagedMethod ??= csMethod.Clone();
newManagedMethod.IsManaged = true;
newManagedMethod.Parameters[i].ParameterType = new CSharpTypeWithAttributes(new CSharpFreeType("ReadOnlySpan<char>"))
{
Attributes = { new CSharpMarshalUsingAttribute("typeof(Utf8CustomMarshaller)") }
};
}
}
}

var returnType = ((CppType)csMethod.ReturnType!.CppElement!);
if (returnType.TryGetElementTypeFromPointer(out var isConstReturn, out var returnElementType))
{
if (returnElementType is CppPrimitiveType { Kind: CppPrimitiveKind.Char })
{
newManagedMethod ??= csMethod.Clone();
csMethod.Name = $"{csMethod.Name}_";
newManagedMethod.IsManaged = true;
newManagedMethod.ReturnType = new CSharpTypeWithAttributes(CSharpPrimitiveType.String())
{
Attributes = { new CSharpMarshalUsingAttribute("typeof(Utf8CustomMarshaller)") { Scope = CSharpAttributeScope.Return } }
};
}
}

if (newManagedMethod != null)
{
var parent = ((ICSharpContainer)csMethod.Parent!);
var indexOf = parent.Members.IndexOf(csMethod);
parent.Members.Insert(indexOf + 1, newManagedMethod);
}
}

protected static void ProcessBoolArgumentsFunction(CSharpMethod csMethod)
{
for (var i = 0; i < csMethod.Parameters.Count; i++)
{
var param = csMethod.Parameters[i];
if (param.ParameterType is CSharpPrimitiveType csPrimitiveType && csPrimitiveType.Kind == CSharpPrimitiveKind.Bool)
{
param.ParameterType = new CSharpTypeWithAttributes(param.ParameterType)
{
Attributes = { new CSharpMarshalAsAttribute(UnmanagedType.U1) }
};
}
}

if (csMethod.ReturnType is CSharpPrimitiveType csPrimitiveType2 && csPrimitiveType2.Kind == CSharpPrimitiveKind.Bool)
{
csMethod.ReturnType = new CSharpTypeWithAttributes(csMethod.ReturnType)
{
Attributes =
{
new CSharpMarshalAsAttribute(UnmanagedType.U1)
{
Scope = CSharpAttributeScope.Return
}
}
};
}
}

private static IEnumerable<CSharpMethod> CollectAllFunctions(CSharpClass csClass)
{
foreach (var csElement in csClass.Members)
Expand Down
12 changes: 12 additions & 0 deletions src/codegen/XenoAtom.Interop.CodeGen/Program.LibDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using XenoAtom.Interop.CodeGen.libdrm;
using XenoAtom.Interop.CodeGen.libgbm;
using XenoAtom.Interop.CodeGen.libgit2;
using XenoAtom.Interop.CodeGen.libkmod;
using XenoAtom.Interop.CodeGen.libshaderc;
using XenoAtom.Interop.CodeGen.musl;
using XenoAtom.Interop.CodeGen.sqlite;
Expand Down Expand Up @@ -224,5 +225,16 @@ sudo apt-get install -y \
Generator = desc => new LibshadercGenerator(desc),
ApkDeps = ["shaderc-dev"],
},
new()
{
Name = "libkmod",
Summary = "This package provides a low-level and modern .NET P/Invoke wrapper around the libkmod API.",
CppDescription = "libkmod is a library for managing kernel modules.",
Url = "https://github.com/kmod-project/kmod/",
UrlDocumentation = "https://github.com/kmod-project/kmod/",
Generator = desc => new LibkmodGenerator(desc),
ApkDeps = ["kmod-dev"],
SupportedArchitectures = [ "linux" ]
},
];
}
148 changes: 148 additions & 0 deletions src/codegen/XenoAtom.Interop.CodeGen/libkmod/LibkmodGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// Licensed under the BSD-Clause 2 license.
// See license.txt file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ClangSharp;
using CppAst;
using CppAst.CodeGen.CSharp;

namespace XenoAtom.Interop.CodeGen.libkmod
{
/// <summary>
/// Generator for Mesa libkmod API.
/// </summary>
internal partial class LibkmodGenerator(LibDescriptor descriptor) : GeneratorBase(descriptor)
{
protected override async Task<CSharpCompilation?> Generate()
{
//var sysIncludes = Apk.GetSysIncludeDirectory("main");
//var mainInclude = Apk.GetIncludeDirectory("main");

var sysFolders = Apk.GetPackageIncludeDirectoryAndDependencies(Descriptor.ApkDeps[0], out var libkmodIncludeFolder);

var sysDirectory = Apk.GetPackageIncludeDirectory("musl-dev");
sysFolders.Insert(0, sysDirectory);
//var linuxHeaders = Apk.GetPackageIncludeDirectory("linux-headers");
//sysFolders.Insert(1, linuxHeaders);

var csOptions = new CSharpConverterOptions()
{
DefaultClassLib = "libkmod",
DefaultNamespace = "XenoAtom.Interop",
DefaultOutputFilePath = "/libkmod_library.generated.cs",
DefaultDllImportNameAndArguments = "LibraryName",
TargetVendor = "linux",
TargetSystem = "gnu",
DefaultCallingConvention = CallingConvention.Cdecl,
Defines =
{
},
AdditionalArguments =
{
//"-nostdinc",
//"-std=c99"
},
SystemIncludeFolders =
{
},
IncludeFolders =
{
libkmodIncludeFolder,
},

PreHeaderText = @"",

DispatchOutputPerInclude = true,
DisableRuntimeMarshalling = true,
AllowMarshalForString = false,
EnableAutoByRef = false,
MapCLongToIntPtr = true,

MappingRules =
{
e => e.Map<CppFunction>("kmod_validate_resources").Type("kmod_resources"),
e => e.Map<CppParameter>("kmod_module_remove_module::flags").Type("kmod_remove"),
e => e.Map<CppParameter>("kmod_module_insert_module::flags").Type("kmod_insert"),
e => e.Map<CppParameter>("kmod_module_probe_insert_module::flags").Type("kmod_probe"),
e => e.Map<CppEnum>("kmod_symbol_bind").Discard(), // Not used in public API but only internally
e => e.Map<CppEnumItem>("_KMOD_MODULE_PAD").Discard(),
e => e.Map<CppFunction>("kmod_set_log_fn").Discard(),
e => e.Map<CppFunction>("vsyslog").Discard(), // discard as it has a va_list
e => e.Map<CppTypedef>("va_list").Discard(), // discard va_list
e => e.Map<CppClass>("__va_list_tag").Discard(), // discard __va_list_tag
}
};

foreach (var folder in sysFolders)
{
csOptions.SystemIncludeFolders.Add(folder);
}
var files = new List<string>()
{
Path.Combine(libkmodIncludeFolder, "libkmod.h"),
};

var csCompilation = CSharpConverter.Convert(files, csOptions);

{
foreach (var message in csCompilation.Diagnostics.Messages)
{
Console.Error.WriteLine(message);
}

if (csCompilation.HasErrors)
{
Console.Error.WriteLine("Unexpected parsing errors");
Environment.Exit(1);
}
}

// Fix enums to flags
foreach (var csEnum in csCompilation.AllEnums)
{
switch (csEnum.Name)
{
case "kmod_remove":
case "kmod_insert":
case "kmod_probe":
case "kmod_filter":
csEnum.IsFlags = true;
break;
case "kmod_module_initstate":
csEnum.IsFlags = false;
break;
}
}

foreach(var csMethod in csCompilation.AllFunctions)
{
ProcessOutputParameter(csMethod);
ProcessBoolArgumentsFunction(csMethod);
ProcessConstStringArguments(csMethod);
}

return csCompilation;
}

private void ProcessOutputParameter(CSharpMethod csFunction)
{
if (csFunction.Name == "kmod_new") return;

foreach (var csParameter in csFunction.Parameters)
{
if (csParameter.ParameterType is CSharpPointerType csPointerType)
{
if (csPointerType.ElementType is CSharpStruct)
{
csParameter.ParameterType = new CSharpRefType(CSharpRefKind.Out, csPointerType.ElementType);
}
}
}
}
}
}
Loading

0 comments on commit 3cf3a49

Please sign in to comment.