diff options
| -rw-r--r-- | tests/projects/csharp/native_aot/src/app/main.cpp | 12 | ||||
| -rw-r--r-- | tests/projects/csharp/native_aot/src/cslib/MathLib.cs | 9 | ||||
| -rw-r--r-- | tests/projects/csharp/native_aot/test.lua | 13 | ||||
| -rw-r--r-- | tests/projects/csharp/native_aot/xmake.lua | 11 | ||||
| -rw-r--r-- | xmake/modules/core/tools/dotnet.lua | 12 | ||||
| -rw-r--r-- | xmake/rules/csharp/config.lua | 8 | ||||
| -rw-r--r-- | xmake/rules/csharp/generator/properties.lua | 23 | ||||
| -rw-r--r-- | xmake/rules/csharp/xmake.lua | 8 |
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") |
