summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/projects/csharp/native_aot/src/app/main.cpp12
-rw-r--r--tests/projects/csharp/native_aot/src/cslib/MathLib.cs9
-rw-r--r--tests/projects/csharp/native_aot/test.lua13
-rw-r--r--tests/projects/csharp/native_aot/xmake.lua11
-rw-r--r--xmake/modules/core/tools/dotnet.lua12
-rw-r--r--xmake/rules/csharp/config.lua8
-rw-r--r--xmake/rules/csharp/generator/properties.lua23
-rw-r--r--xmake/rules/csharp/xmake.lua8
8 files changed, 92 insertions, 4 deletions
diff --git a/tests/projects/csharp/native_aot/src/app/main.cpp b/tests/projects/csharp/native_aot/src/app/main.cpp
new file mode 100644
index 000000000..070ad7de6
--- /dev/null
+++ b/tests/projects/csharp/native_aot/src/app/main.cpp
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern "C" {
+ int cs_add(int a, int b);
+ int cs_multiply(int a, int b);
+}
+
+int main() {
+ printf("cs_add(3,4)=%d\n", cs_add(3, 4));
+ printf("cs_multiply(5,6)=%d\n", cs_multiply(5, 6));
+ return 0;
+}
diff --git a/tests/projects/csharp/native_aot/src/cslib/MathLib.cs b/tests/projects/csharp/native_aot/src/cslib/MathLib.cs
new file mode 100644
index 000000000..83255a4b3
--- /dev/null
+++ b/tests/projects/csharp/native_aot/src/cslib/MathLib.cs
@@ -0,0 +1,9 @@
+using System.Runtime.InteropServices;
+
+public static class MathLib {
+ [UnmanagedCallersOnly(EntryPoint = "cs_add")]
+ public static int Add(int a, int b) => a + b;
+
+ [UnmanagedCallersOnly(EntryPoint = "cs_multiply")]
+ public static int Multiply(int a, int b) => a * b;
+}
diff --git a/tests/projects/csharp/native_aot/test.lua b/tests/projects/csharp/native_aot/test.lua
new file mode 100644
index 000000000..d909316b7
--- /dev/null
+++ b/tests/projects/csharp/native_aot/test.lua
@@ -0,0 +1,13 @@
+import("detect.sdks.find_dotnet")
+
+function test_build(t)
+ if is_subhost("msys") then
+ return t:skip("csharp not supported on msys")
+ end
+ local dotnet = find_dotnet()
+ if dotnet and dotnet.sdkver then
+ t:build()
+ else
+ return t:skip("dotnet sdk not found")
+ end
+end
diff --git a/tests/projects/csharp/native_aot/xmake.lua b/tests/projects/csharp/native_aot/xmake.lua
new file mode 100644
index 000000000..92f264095
--- /dev/null
+++ b/tests/projects/csharp/native_aot/xmake.lua
@@ -0,0 +1,11 @@
+add_rules("mode.debug", "mode.release")
+
+target("cslib")
+ set_kind("shared")
+ add_files("src/cslib/*.cs")
+ set_values("csharp.publish_aot", "true")
+
+target("app")
+ set_kind("binary")
+ add_deps("cslib")
+ add_files("src/app/*.cpp")
diff --git a/xmake/modules/core/tools/dotnet.lua b/xmake/modules/core/tools/dotnet.lua
index 9a502b616..90d585b87 100644
--- a/xmake/modules/core/tools/dotnet.lua
+++ b/xmake/modules/core/tools/dotnet.lua
@@ -97,7 +97,10 @@ end
-- make the build arguments list
function buildargv(self, sourcefiles, targetkind, targetfile, flags, opt)
- local argv = {"build"}
+ -- use `dotnet publish` for NativeAOT, otherwise `dotnet build`
+ local target = opt and opt.target
+ local publish_aot = target and target:values("csharp.publish_aot")
+ local argv = {publish_aot and "publish" or "build"}
-- add .csproj file
local csprojfile = _get_csprojfile(opt)
@@ -123,4 +126,11 @@ function build(self, sourcefiles, targetkind, targetfile, flags, opt)
os.mkdir(path.directory(targetfile))
local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags, opt)
os.runv(program, argv, {envs = self:runenvs()})
+
+ -- fix install_name for NativeAOT shared library on macOS
+ local target = opt and opt.target
+ local publish_aot = target and target:values("csharp.publish_aot")
+ if publish_aot and targetkind == "shared" and self:is_plat("macosx", "iphoneos", "watchos") then
+ os.runv("install_name_tool", {"-id", "@rpath/" .. path.filename(targetfile), targetfile})
+ end
end
diff --git a/xmake/rules/csharp/config.lua b/xmake/rules/csharp/config.lua
index e9dbc71e0..e3a728922 100644
--- a/xmake/rules/csharp/config.lua
+++ b/xmake/rules/csharp/config.lua
@@ -45,6 +45,14 @@ function main(target)
target:data_set("csharp.csproj", csprojfile)
+ -- for NativeAOT shared library, export targetfile directly for C/C++ consumers
+ -- dotnet outputs without lib prefix, so we use syslinks with full path
+ local publish_aot = target:values("csharp.publish_aot")
+ if publish_aot and target:is_shared() then
+ target:data_set("inherit.links.deplink", false)
+ target:add("ldflags", target:targetfile(), {interface = true, force = true})
+ end
+
-- add native shared library search paths for P/Invoke
for _, dep in ipairs(target:orderdeps()) do
if dep:is_shared() and not dep:rule("csharp.build") then
diff --git a/xmake/rules/csharp/generator/properties.lua b/xmake/rules/csharp/generator/properties.lua
index 15702eae4..0fbab66e3 100644
--- a/xmake/rules/csharp/generator/properties.lua
+++ b/xmake/rules/csharp/generator/properties.lua
@@ -67,6 +67,27 @@ function _resolve_assembly_name(context)
end
+-- resolve runtime identifier from user config or auto-detect from target plat/arch
+-- e.g. "osx-x64", "osx-arm64", "linux-x64", "win-x64"
+function _resolve_runtime_identifier(context)
+ local rid = _get_target_value(context.target, "csharp.runtime_identifier")
+ if rid then
+ return rid
+ end
+ -- auto-detect RID when publish_aot is enabled
+ local publish_aot = _get_target_value(context.target, "csharp.publish_aot")
+ if not publish_aot then
+ return nil
+ end
+ local target = context.target
+ local plat = target:plat()
+ local arch = target:arch()
+ local rid_arch = ({x86_64 = "x64", i386 = "x86", x64 = "x64", x86 = "x86",
+ arm64 = "arm64", ["arm64-v8a"] = "arm64", armv7 = "arm"})[arch] or arch
+ local rid_os = ({macosx = "osx", linux = "linux", windows = "win", mingw = "win"})[plat] or plat
+ return rid_os .. "-" .. rid_arch
+end
+
-- register a single-value csharp.* property entry
function _register_property(register, suffix, xml, default, extra)
local entry = table.join({
@@ -128,7 +149,7 @@ function main()
_register_property(register, "generate_documentation_file", "GenerateDocumentationFile")
_register_property(register, "documentation_file", "DocumentationFile")
- _register_property(register, "runtime_identifier", "RuntimeIdentifier")
+ register({kind = "property", xml = "RuntimeIdentifier", resolve = _resolve_runtime_identifier})
_register_list_property(register, "runtime_identifiers", "RuntimeIdentifiers")
_register_property(register, "self_contained", "SelfContained")
_register_property(register, "use_app_host", "UseAppHost")
diff --git a/xmake/rules/csharp/xmake.lua b/xmake/rules/csharp/xmake.lua
index 9a0a6e43b..603af08c3 100644
--- a/xmake/rules/csharp/xmake.lua
+++ b/xmake/rules/csharp/xmake.lua
@@ -115,10 +115,14 @@
rule("csharp.build")
set_sourcekinds("cs")
on_load(function (target)
- -- dotnet always outputs .dll for libraries, and no prefix
if target:is_shared() or target:is_static() then
+ -- dotnet always outputs without lib prefix
target:set("prefixname", "")
- target:set("extension", ".dll")
+ -- managed libraries use .dll, NativeAOT uses native format (.dylib/.so/.dll)
+ local publish_aot = target:values("csharp.publish_aot")
+ if not publish_aot then
+ target:set("extension", ".dll")
+ end
end
end)
on_config("config")