From 9946d1814f4af9ef67e5accd9404e0fc69290f6f Mon Sep 17 00:00:00 2001 From: JassJam <0139ne@gmail.com> Date: Mon, 23 Feb 2026 12:28:50 +0000 Subject: feat: add initial test files --- tests/projects/csharp/console/xmake.lua | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/projects/csharp/console/xmake.lua (limited to 'tests/projects/csharp/console/xmake.lua') diff --git a/tests/projects/csharp/console/xmake.lua b/tests/projects/csharp/console/xmake.lua new file mode 100644 index 000000000..25cd801f0 --- /dev/null +++ b/tests/projects/csharp/console/xmake.lua @@ -0,0 +1,6 @@ +add_rules("mode.debug", "mode.release") + +target("test") + set_kind("binary") + add_rules("csharp") + add_files("src/Program.cs", "src/test.csproj") -- cgit v1.3.1 From a92e7c4087443cd91dafe14d2a5aa316a288b7c5 Mon Sep 17 00:00:00 2001 From: JassJam <0139ne@gmail.com> Date: Sat, 28 Feb 2026 15:37:56 +0000 Subject: feat: generate csproj on demand --- tests/projects/csharp/console/src/test.csproj | 9 - tests/projects/csharp/console/xmake.lua | 2 +- .../console_with_runtime_json/src/app.csproj | 14 - .../csharp/console_with_runtime_json/xmake.lua | 2 +- .../csharp/exe_with_library/src/app/app.csproj | 12 - .../csharp/exe_with_library/src/lib/lib.csproj | 8 - tests/projects/csharp/exe_with_library/xmake.lua | 4 +- .../csharp/exe_with_package/src/app.csproj | 12 - tests/projects/csharp/exe_with_package/xmake.lua | 4 +- tests/projects/csharp/existing_csproj/.gitignore | 6 + tests/projects/csharp/existing_csproj/Program.cs | 2 + .../csharp/existing_csproj/existing_csproj.csproj | 10 + tests/projects/csharp/existing_csproj/test.lua | 10 + tests/projects/csharp/existing_csproj/xmake.lua | 6 + .../multiple_library/src/libalpha/libalpha.csproj | 8 - .../multiple_library/src/libbeta/libbeta.csproj | 11 - .../multiple_library/src/sample/sample.csproj | 14 - tests/projects/csharp/multiple_library/xmake.lua | 6 +- .../projects/csharp/web_project/src/webapp.csproj | 8 - tests/projects/csharp/web_project/xmake.lua | 3 +- xmake/rules/csharp/buildcmd.lua | 36 ++- xmake/rules/csharp/clean.lua | 2 +- xmake/rules/csharp/csharp_common.lua | 160 ----------- xmake/rules/csharp/install.lua | 4 +- xmake/rules/csharp/installcmd.lua | 4 +- xmake/rules/csharp/load.lua | 21 +- xmake/rules/csharp/modules/csharp_common.lua | 232 ++++++++++++++++ xmake/rules/csharp/modules/csproj_generator.lua | 301 ++++++++++++++++++++ xmake/rules/csharp/modules/itemgroups.lua | 166 +++++++++++ xmake/rules/csharp/modules/properties.lua | 307 +++++++++++++++++++++ xmake/rules/csharp/xmake.lua | 83 +++++- 31 files changed, 1184 insertions(+), 283 deletions(-) delete mode 100644 tests/projects/csharp/console/src/test.csproj delete mode 100644 tests/projects/csharp/console_with_runtime_json/src/app.csproj delete mode 100644 tests/projects/csharp/exe_with_library/src/app/app.csproj delete mode 100644 tests/projects/csharp/exe_with_library/src/lib/lib.csproj delete mode 100644 tests/projects/csharp/exe_with_package/src/app.csproj create mode 100644 tests/projects/csharp/existing_csproj/.gitignore create mode 100644 tests/projects/csharp/existing_csproj/Program.cs create mode 100644 tests/projects/csharp/existing_csproj/existing_csproj.csproj create mode 100644 tests/projects/csharp/existing_csproj/test.lua create mode 100644 tests/projects/csharp/existing_csproj/xmake.lua delete mode 100644 tests/projects/csharp/multiple_library/src/libalpha/libalpha.csproj delete mode 100644 tests/projects/csharp/multiple_library/src/libbeta/libbeta.csproj delete mode 100644 tests/projects/csharp/multiple_library/src/sample/sample.csproj delete mode 100644 tests/projects/csharp/web_project/src/webapp.csproj delete mode 100644 xmake/rules/csharp/csharp_common.lua create mode 100644 xmake/rules/csharp/modules/csharp_common.lua create mode 100644 xmake/rules/csharp/modules/csproj_generator.lua create mode 100644 xmake/rules/csharp/modules/itemgroups.lua create mode 100644 xmake/rules/csharp/modules/properties.lua (limited to 'tests/projects/csharp/console/xmake.lua') diff --git a/tests/projects/csharp/console/src/test.csproj b/tests/projects/csharp/console/src/test.csproj deleted file mode 100644 index 9dbab4973..000000000 --- a/tests/projects/csharp/console/src/test.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - Exe - net8.0 - enable - enable - - - diff --git a/tests/projects/csharp/console/xmake.lua b/tests/projects/csharp/console/xmake.lua index 25cd801f0..3288c96a8 100644 --- a/tests/projects/csharp/console/xmake.lua +++ b/tests/projects/csharp/console/xmake.lua @@ -3,4 +3,4 @@ add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_rules("csharp") - add_files("src/Program.cs", "src/test.csproj") + add_files("src/Program.cs") diff --git a/tests/projects/csharp/console_with_runtime_json/src/app.csproj b/tests/projects/csharp/console_with_runtime_json/src/app.csproj deleted file mode 100644 index 4e754bb15..000000000 --- a/tests/projects/csharp/console_with_runtime_json/src/app.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - net8.0 - enable - enable - - - - PreserveNewest - - - - diff --git a/tests/projects/csharp/console_with_runtime_json/xmake.lua b/tests/projects/csharp/console_with_runtime_json/xmake.lua index 8d8539b26..474eda548 100644 --- a/tests/projects/csharp/console_with_runtime_json/xmake.lua +++ b/tests/projects/csharp/console_with_runtime_json/xmake.lua @@ -3,4 +3,4 @@ add_rules("mode.debug", "mode.release") target("app") set_kind("binary") add_rules("csharp") - add_files("src/Program.cs", "src/app.csproj") + add_files("src/Program.cs") diff --git a/tests/projects/csharp/exe_with_library/src/app/app.csproj b/tests/projects/csharp/exe_with_library/src/app/app.csproj deleted file mode 100644 index e5e49a685..000000000 --- a/tests/projects/csharp/exe_with_library/src/app/app.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - net8.0 - enable - enable - - - - - - diff --git a/tests/projects/csharp/exe_with_library/src/lib/lib.csproj b/tests/projects/csharp/exe_with_library/src/lib/lib.csproj deleted file mode 100644 index 30c56ecb5..000000000 --- a/tests/projects/csharp/exe_with_library/src/lib/lib.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - net8.0 - enable - enable - - - diff --git a/tests/projects/csharp/exe_with_library/xmake.lua b/tests/projects/csharp/exe_with_library/xmake.lua index 063e051db..f8549444e 100644 --- a/tests/projects/csharp/exe_with_library/xmake.lua +++ b/tests/projects/csharp/exe_with_library/xmake.lua @@ -3,10 +3,10 @@ add_rules("mode.debug", "mode.release") target("mylib") set_kind("shared") add_rules("csharp") - add_files("src/lib/*.cs", "src/lib/lib.csproj") + add_files("src/lib/*.cs") target("app") set_kind("binary") add_rules("csharp") add_deps("mylib") - add_files("src/app/*.cs", "src/app/app.csproj") + add_files("src/app/*.cs") diff --git a/tests/projects/csharp/exe_with_package/src/app.csproj b/tests/projects/csharp/exe_with_package/src/app.csproj deleted file mode 100644 index 0521e2a0c..000000000 --- a/tests/projects/csharp/exe_with_package/src/app.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - net8.0 - enable - enable - - - - - - diff --git a/tests/projects/csharp/exe_with_package/xmake.lua b/tests/projects/csharp/exe_with_package/xmake.lua index 8d8539b26..6ec474822 100644 --- a/tests/projects/csharp/exe_with_package/xmake.lua +++ b/tests/projects/csharp/exe_with_package/xmake.lua @@ -1,6 +1,8 @@ add_rules("mode.debug", "mode.release") +add_requires("nuget::Humanizer.Core 2.14.1") target("app") set_kind("binary") add_rules("csharp") - add_files("src/Program.cs", "src/app.csproj") + add_files("src/Program.cs") + add_packages("nuget::Humanizer.Core") diff --git a/tests/projects/csharp/existing_csproj/.gitignore b/tests/projects/csharp/existing_csproj/.gitignore new file mode 100644 index 000000000..6b8d3af38 --- /dev/null +++ b/tests/projects/csharp/existing_csproj/.gitignore @@ -0,0 +1,6 @@ +.xmake/ +build/ +bin/ +obj/ +vsxmake*/ +.vs/ diff --git a/tests/projects/csharp/existing_csproj/Program.cs b/tests/projects/csharp/existing_csproj/Program.cs new file mode 100644 index 000000000..3751555cb --- /dev/null +++ b/tests/projects/csharp/existing_csproj/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/tests/projects/csharp/existing_csproj/existing_csproj.csproj b/tests/projects/csharp/existing_csproj/existing_csproj.csproj new file mode 100644 index 000000000..ed9781c22 --- /dev/null +++ b/tests/projects/csharp/existing_csproj/existing_csproj.csproj @@ -0,0 +1,10 @@ + + + + Exe + net10.0 + enable + enable + + + diff --git a/tests/projects/csharp/existing_csproj/test.lua b/tests/projects/csharp/existing_csproj/test.lua new file mode 100644 index 000000000..5ab8adc69 --- /dev/null +++ b/tests/projects/csharp/existing_csproj/test.lua @@ -0,0 +1,10 @@ +import("lib.detect.find_tool") + +function test_build(t) + local dotnet = find_tool("dotnet") + if dotnet then + t:build() + else + return t:skip("dotnet not found") + end +end diff --git a/tests/projects/csharp/existing_csproj/xmake.lua b/tests/projects/csharp/existing_csproj/xmake.lua new file mode 100644 index 000000000..95e5e45d9 --- /dev/null +++ b/tests/projects/csharp/existing_csproj/xmake.lua @@ -0,0 +1,6 @@ +add_rules("mode.debug", "mode.release") + +target("test") + set_kind("binary") + add_rules("csharp") + add_files("existing_csproj.csproj") diff --git a/tests/projects/csharp/multiple_library/src/libalpha/libalpha.csproj b/tests/projects/csharp/multiple_library/src/libalpha/libalpha.csproj deleted file mode 100644 index 30c56ecb5..000000000 --- a/tests/projects/csharp/multiple_library/src/libalpha/libalpha.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - net8.0 - enable - enable - - - diff --git a/tests/projects/csharp/multiple_library/src/libbeta/libbeta.csproj b/tests/projects/csharp/multiple_library/src/libbeta/libbeta.csproj deleted file mode 100644 index 15502d321..000000000 --- a/tests/projects/csharp/multiple_library/src/libbeta/libbeta.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - net8.0 - enable - enable - - - - - - diff --git a/tests/projects/csharp/multiple_library/src/sample/sample.csproj b/tests/projects/csharp/multiple_library/src/sample/sample.csproj deleted file mode 100644 index 459440d0e..000000000 --- a/tests/projects/csharp/multiple_library/src/sample/sample.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - - - - - diff --git a/tests/projects/csharp/multiple_library/xmake.lua b/tests/projects/csharp/multiple_library/xmake.lua index b4be98c99..db3f65811 100644 --- a/tests/projects/csharp/multiple_library/xmake.lua +++ b/tests/projects/csharp/multiple_library/xmake.lua @@ -3,16 +3,16 @@ add_rules("mode.debug", "mode.release") target("libalpha") set_kind("shared") add_rules("csharp") - add_files("src/libalpha/*.cs", "src/libalpha/libalpha.csproj") + add_files("src/libalpha/*.cs") target("libbeta") set_kind("shared") add_rules("csharp") add_deps("libalpha") - add_files("src/libbeta/*.cs", "src/libbeta/libbeta.csproj") + add_files("src/libbeta/*.cs") target("sample") set_kind("binary") add_rules("csharp") add_deps("libbeta") - add_files("src/sample/*.cs", "src/sample/sample.csproj") + add_files("src/sample/*.cs") diff --git a/tests/projects/csharp/web_project/src/webapp.csproj b/tests/projects/csharp/web_project/src/webapp.csproj deleted file mode 100644 index 4715481ee..000000000 --- a/tests/projects/csharp/web_project/src/webapp.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - net8.0 - enable - enable - - - diff --git a/tests/projects/csharp/web_project/xmake.lua b/tests/projects/csharp/web_project/xmake.lua index d1e5504c3..56bcad79c 100644 --- a/tests/projects/csharp/web_project/xmake.lua +++ b/tests/projects/csharp/web_project/xmake.lua @@ -3,4 +3,5 @@ add_rules("mode.debug", "mode.release") target("webapp") set_kind("binary") add_rules("csharp") - add_files("src/Program.cs", "src/webapp.csproj") + add_values("csharp.sdk", "Microsoft.NET.Sdk.Web") + add_files("src/Program.cs") diff --git a/xmake/rules/csharp/buildcmd.lua b/xmake/rules/csharp/buildcmd.lua index e3c45ace8..b8f85360a 100644 --- a/xmake/rules/csharp/buildcmd.lua +++ b/xmake/rules/csharp/buildcmd.lua @@ -18,10 +18,35 @@ -- @file buildcmd.lua -- -import("csharp_common") +import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) + +local function _get_output_mtime(target, targetfile, targetdirabs) + local mtime = targetfile and os.mtime(targetfile) or nil + if mtime then + return mtime + end + + if targetdirabs and os.isdir(targetdirabs) then + -- dotnet can place outputs under tfm/rid subdirectories depending on + -- project properties, so scan recursively for a matching assembly name. + local basename = target:basename() or target:name() + for _, ext in ipairs({".exe", ".dll", ".so", ".dylib"}) do + for _, file in ipairs(os.files(path.join(targetdirabs, "**", basename .. ext))) do + local filemtime = os.mtime(file) + if filemtime and (not mtime or filemtime > mtime) then + mtime = filemtime + end + end + end + if not mtime then + mtime = os.mtime(targetdirabs) + end + end + return mtime +end function main(target, batchcmds, opt) - local csprojfile = assert(csharp_common.find_csproj(target), "target(%s): missing csharp .csproj file!", target:name()) + local csprojfile = assert(csharp_common.find_or_generate_csproj(target), "target(%s): missing csharp .csproj file!", target:name()) local dotnet = csharp_common.get_dotnet_program(target) local configuration = csharp_common.build_mode_to_configuration() local verbosity = csharp_common.get_dotnet_verbosity() @@ -54,9 +79,10 @@ function main(target, batchcmds, opt) local targetfile = target:targetfile() if targetfile then - local sourcefiles = target:sourcefiles() - batchcmds:add_depfiles(sourcefiles) - batchcmds:set_depmtime(os.mtime(targetfile)) + local depfiles = table.wrap(target:sourcefiles()) + table.insert(depfiles, csprojfile) + batchcmds:add_depfiles(table.unique(depfiles)) + batchcmds:set_depmtime(_get_output_mtime(target, targetfile, targetdirabs)) batchcmds:set_depcache(target:dependfile(targetfile)) end end diff --git a/xmake/rules/csharp/clean.lua b/xmake/rules/csharp/clean.lua index 863e97b50..ce683268c 100644 --- a/xmake/rules/csharp/clean.lua +++ b/xmake/rules/csharp/clean.lua @@ -19,7 +19,7 @@ -- import("target.action.clean", {alias = "_do_clean_target"}) -import("csharp_common") +import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) function main(target, opt) _do_clean_target(target) diff --git a/xmake/rules/csharp/csharp_common.lua b/xmake/rules/csharp/csharp_common.lua deleted file mode 100644 index 1df548c60..000000000 --- a/xmake/rules/csharp/csharp_common.lua +++ /dev/null @@ -1,160 +0,0 @@ ---!A cross-platform build utility based on Lua --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- Copyright (C) 2015-present, Xmake Open Source Community. --- --- @author JassJam --- @file csharp_common.lua --- - -import("core.base.option") - -function _map_rid_arch(arch) - arch = (arch or ""):lower() - if arch == "x64" or arch == "x86_64" or arch == "amd64" then - return "x64" - elseif arch == "x86" or arch == "i386" then - return "x86" - elseif arch == "arm64" then - return "arm64" - elseif arch == "arm" or arch == "armv7" then - return "arm" - elseif arch == "riscv64" then - return "riscv64" - end - return nil -end - -function find_csproj(target) - local csproj = target:data("csharp.csproj") - if csproj then - return csproj - end - for _, sourcefile in ipairs(target:sourcefiles()) do - if path.extension(sourcefile):lower() == ".csproj" then - local csprojabs = path.is_absolute(sourcefile) and sourcefile or path.absolute(sourcefile, os.projectdir()) - if os.isfile(csprojabs) then - return csprojabs - end - end - end - return nil -end - -function build_mode_to_configuration() - local mode - if type(get_config) == "function" then - mode = get_config("mode") - end - if not mode and type(is_mode) == "function" then - if is_mode("debug") then - mode = "debug" - elseif is_mode("release") then - mode = "release" - end - end - mode = mode or "release" - local mode_lower = mode:lower() - if mode_lower == "debug" then - return "Debug" - elseif mode_lower == "release" then - return "Release" - end - return mode:sub(1, 1):upper() .. mode:sub(2) -end - -function get_runtime_identifier(target) - local rid = target:values("csharp.runtime_identifier") - if type(rid) == "table" then - rid = rid[1] - end - if rid and #rid > 0 then - return rid - end - local arch = _map_rid_arch(target:arch()) - if not arch then - return nil - end - local plat = target:plat() - if plat == "windows" or plat == "mingw" or plat == "msys" or plat == "cygwin" then - return "win-" .. arch - elseif plat == "linux" then - return "linux-" .. arch - elseif plat == "macosx" then - return "osx-" .. arch - end - return nil -end - -function append_target_flags(target, argv) - local flags = {} - table.join2(flags, table.wrap(target:get("csflags"))) - table.join2(flags, table.wrap(target:get("ldflags"))) - table.join2(flags, table.wrap(target:get("arflags"))) - table.join2(flags, table.wrap(target:get("shflags"))) - for _, flag in ipairs(flags) do - if flag and #flag > 0 then - table.insert(argv, flag) - end - end -end - -function get_dotnet_runopt(csprojfile) - return { - curdir = path.directory(csprojfile), - envs = { - DOTNET_NOLOGO = "1", - DOTNET_CLI_TELEMETRY_OPTOUT = "1", - DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1", - DOTNET_GENERATE_ASPNET_CERTIFICATE = "0", - DOTNET_ADD_GLOBAL_TOOLS_TO_PATH = "0" - } - } -end - -function get_dotnet_verbosity() - if option.get("diagnosis") then - return "diagnostic" - end - return "quiet" -end - -function get_dotnet_program(target) - local function _get_configured_program(toolkind) - if target:get("toolset." .. toolkind) then - local program = target:tool(toolkind) - if program and #program > 0 then - return program - end - end - end - - local program = nil - if target:is_binary() then - program = _get_configured_program("ld") - elseif target:is_shared() then - program = _get_configured_program("sh") - else - program = _get_configured_program("cs") - end - if program then - return program - end - - program = target:tool("cs") - if program and #program > 0 then - return program - end - return "dotnet" -end diff --git a/xmake/rules/csharp/install.lua b/xmake/rules/csharp/install.lua index 34109a054..32cc9e8e0 100644 --- a/xmake/rules/csharp/install.lua +++ b/xmake/rules/csharp/install.lua @@ -18,7 +18,7 @@ -- @file install.lua -- -import("csharp_common") +import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) function main(target, opt) local function _q(arg) @@ -29,7 +29,7 @@ function main(target, opt) return arg end - local csprojfile = assert(csharp_common.find_csproj(target), "target(%s): missing csharp .csproj file!", target:name()) + local csprojfile = assert(csharp_common.find_or_generate_csproj(target), "target(%s): missing csharp .csproj file!", target:name()) local dotnet = csharp_common.get_dotnet_program(target) local configuration = csharp_common.build_mode_to_configuration() local verbosity = csharp_common.get_dotnet_verbosity() diff --git a/xmake/rules/csharp/installcmd.lua b/xmake/rules/csharp/installcmd.lua index 76c051a59..7e1e385b4 100644 --- a/xmake/rules/csharp/installcmd.lua +++ b/xmake/rules/csharp/installcmd.lua @@ -18,10 +18,10 @@ -- @file installcmd.lua -- -import("csharp_common") +import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) function main(target, batchcmds, opt) - local csprojfile = assert(csharp_common.find_csproj(target), "target(%s): missing csharp .csproj file!", target:name()) + local csprojfile = assert(csharp_common.find_or_generate_csproj(target), "target(%s): missing csharp .csproj file!", target:name()) local dotnet = csharp_common.get_dotnet_program(target) local configuration = csharp_common.build_mode_to_configuration() local verbosity = csharp_common.get_dotnet_verbosity() diff --git a/xmake/rules/csharp/load.lua b/xmake/rules/csharp/load.lua index 0811cf8d0..14b53a1fa 100644 --- a/xmake/rules/csharp/load.lua +++ b/xmake/rules/csharp/load.lua @@ -18,6 +18,8 @@ -- @file load.lua -- +import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) + function main(target) local targetdir = target:targetdir() if targetdir and path.filename(targetdir) ~= target:name() then @@ -40,12 +42,21 @@ function main(target) table.insert(csprojfiles, sourcefile) end end - assert(#csprojfiles > 0, "target(%s): csharp requires one .csproj in add_files()!", target:name()) - assert(#csprojfiles == 1, "target(%s): csharp only supports one .csproj file!", target:name()) + assert(#csprojfiles <= 1, "target(%s): csharp only supports one .csproj file!", target:name()) - local csprojfile = csprojfiles[1] - local csprojabs = path.is_absolute(csprojfile) and csprojfile or path.absolute(csprojfile, os.projectdir()) - assert(os.isfile(csprojabs), "target(%s): csharp .csproj not found: %s", target:name(), csprojfile) + local csprojabs = nil + if #csprojfiles == 1 then + local csprojfile = csprojfiles[1] + local csprojpath = path.is_absolute(csprojfile) and csprojfile or path.absolute(csprojfile, os.projectdir()) + if os.isfile(csprojpath) then + csprojabs = csprojpath + end + end + + if not csprojabs then + csprojabs = csharp_common.find_or_generate_csproj(target, {skip_deps = true}) + end + assert(csprojabs, "target(%s): csharp failed to resolve or generate .csproj file!", target:name()) if not target:get("filename") and not target:get("basename") then target:set("basename", path.basename(csprojabs)) diff --git a/xmake/rules/csharp/modules/csharp_common.lua b/xmake/rules/csharp/modules/csharp_common.lua new file mode 100644 index 000000000..dce35021a --- /dev/null +++ b/xmake/rules/csharp/modules/csharp_common.lua @@ -0,0 +1,232 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author JassJam +-- @file csharp_common.lua +-- + +import("core.base.option") +import("core.project.config") +import("csproj_generator", {rootdir = os.scriptdir(), alias = "generate_csproj"}) + +function _is_csharp_target(target) + if target:rule("csharp") then + return true + end + for _, sourcefile in ipairs(target:sourcefiles()) do + local ext = path.extension(sourcefile):lower() + if ext == ".cs" or ext == ".csproj" then + return true + end + end + return false +end + +function _generated_csproj_path(target) + local targetkey = target:fullname():replace("::", path.sep()) + local csprojdir = path.join(config.directory(), "rules", "csharp", targetkey, target:plat(), target:arch()) + local csprojname = target:name() .. ".csproj" + return path.join(csprojdir, csprojname) +end + +function _map_rid_arch(arch) + arch = (arch or ""):lower() + if arch == "x64" or arch == "x86_64" or arch == "amd64" then + return "x64" + elseif arch == "x86" or arch == "i386" then + return "x86" + elseif arch == "arm64" then + return "arm64" + elseif arch == "arm" or arch == "armv7" then + return "arm" + elseif arch == "riscv64" then + return "riscv64" + end + return nil +end + +function find_csproj(target) + local csproj = target:data("csharp.csproj") + if csproj then + return csproj + end + for _, sourcefile in ipairs(target:sourcefiles()) do + if path.extension(sourcefile):lower() == ".csproj" then + local csprojabs = path.is_absolute(sourcefile) and sourcefile or path.absolute(sourcefile, os.projectdir()) + if os.isfile(csprojabs) then + return csprojabs + end + end + end + return nil +end + +function find_or_generate_csproj(target, opt) + opt = opt or {} + local csproj = find_csproj(target) + local generated = target:data("csharp.csproj.generated") + local generated_with_deps = target:data("csharp.csproj.generated.with_deps") + + -- prefer existing source .csproj directly + if csproj and not generated then + return csproj + end + + -- generated .csproj in memory cache + if csproj and generated then + if opt.skip_deps or generated_with_deps then + return csproj + end + end + + if not _is_csharp_target(target) then + return nil + end + + local csprojfile = csproj or _generated_csproj_path(target) + local generated_now = false + + -- in load phase (skip_deps), reuse existing generated file to avoid + -- touching mtime and causing unnecessary rebuilds. + if not (opt.skip_deps and os.isfile(csprojfile)) then + generate_csproj(target, csprojfile, table.join(opt, { + is_csharp_target = _is_csharp_target, + find_or_generate_csproj = find_or_generate_csproj + })) + generated_now = true + end + + target:data_set("csharp.csproj", csprojfile) + target:data_set("csharp.csproj.generated", true) + if opt.skip_deps then + -- keep this conservative in load phase: build/install phase will + -- generate a deps-enabled project if needed, and content checks avoid + -- unnecessary rewrites. + if generated_now or generated_with_deps == nil then + target:data_set("csharp.csproj.generated.with_deps", false) + end + else + target:data_set("csharp.csproj.generated.with_deps", true) + end + return csprojfile +end + +function build_mode_to_configuration() + local mode + if type(get_config) == "function" then + mode = get_config("mode") + end + if not mode and type(is_mode) == "function" then + if is_mode("debug") then + mode = "debug" + elseif is_mode("release") then + mode = "release" + end + end + mode = mode or "release" + local mode_lower = mode:lower() + if mode_lower == "debug" then + return "Debug" + elseif mode_lower == "release" then + return "Release" + end + return mode:sub(1, 1):upper() .. mode:sub(2) +end + +function get_runtime_identifier(target) + local rid = target:values("csharp.runtime_identifier") + if type(rid) == "table" then + rid = rid[1] + end + if rid and #rid > 0 then + return rid + end + local arch = _map_rid_arch(target:arch()) + if not arch then + return nil + end + local plat = target:plat() + if plat == "windows" or plat == "mingw" or plat == "msys" or plat == "cygwin" then + return "win-" .. arch + elseif plat == "linux" then + return "linux-" .. arch + elseif plat == "macosx" then + return "osx-" .. arch + end + return nil +end + +function append_target_flags(target, argv) + local flags = {} + table.join2(flags, table.wrap(target:get("csflags"))) + table.join2(flags, table.wrap(target:get("ldflags"))) + table.join2(flags, table.wrap(target:get("arflags"))) + table.join2(flags, table.wrap(target:get("shflags"))) + for _, flag in ipairs(flags) do + if flag and #flag > 0 then + table.insert(argv, flag) + end + end +end + +function get_dotnet_runopt(csprojfile) + return { + curdir = path.directory(csprojfile), + envs = { + DOTNET_NOLOGO = "1", + DOTNET_CLI_TELEMETRY_OPTOUT = "1", + DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1", + DOTNET_GENERATE_ASPNET_CERTIFICATE = "0", + DOTNET_ADD_GLOBAL_TOOLS_TO_PATH = "0" + } + } +end + +function get_dotnet_verbosity() + if option.get("diagnosis") then + return "diagnostic" + end + return "quiet" +end + +function get_dotnet_program(target) + local function _get_configured_program(toolkind) + if target:get("toolset." .. toolkind) then + local program = target:tool(toolkind) + if program and #program > 0 then + return program + end + end + end + + local program = nil + if target:is_binary() then + program = _get_configured_program("ld") + elseif target:is_shared() then + program = _get_configured_program("sh") + else + program = _get_configured_program("cs") + end + if program then + return program + end + + program = target:tool("cs") + if program and #program > 0 then + return program + end + return "dotnet" +end diff --git a/xmake/rules/csharp/modules/csproj_generator.lua b/xmake/rules/csharp/modules/csproj_generator.lua new file mode 100644 index 000000000..0f94ed806 --- /dev/null +++ b/xmake/rules/csharp/modules/csproj_generator.lua @@ -0,0 +1,301 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author JassJam +-- @file csproj_generator.lua +-- + +import("properties", {rootdir = os.scriptdir(), alias = "csharp_properties"}) +import("itemgroups", {rootdir = os.scriptdir(), alias = "csharp_itemgroups"}) + +function _xml_escape(value) + value = tostring(value or "") + value = value:gsub("&", "&") + value = value:gsub("<", "<") + value = value:gsub(">", ">") + value = value:gsub("\"", """) + value = value:gsub("'", "'") + return value +end + +function _format_attributes(attrs) + if type(attrs) ~= "table" then + return "" + end + local keys = {} + for key, value in pairs(attrs) do + if value ~= nil and value ~= "" then + table.insert(keys, key) + end + end + table.sort(keys) + if #keys == 0 then + return "" + end + local chunks = {} + for _, key in ipairs(keys) do + table.insert(chunks, string.format(" %s=\"%s\"", key, _xml_escape(attrs[key]))) + end + return table.concat(chunks) +end + +function _get_csharp_value(target, name, defaultval) + local val = target:values(name) + if type(val) == "table" then + val = val[1] + end + if val == nil or val == "" then + return defaultval + end + return val +end + +function _resolve_registry_value(entry, target, context) + if entry.resolve then + return entry.resolve(context) + end + if entry.value_type == "list" then + local values = table.wrap(target:values(entry.lua_key)) + if #values == 0 and entry.default ~= nil then + values = table.wrap(entry.default) + end + if #values > 0 then + local items = {} + for _, value in ipairs(values) do + if value ~= nil and value ~= "" then + table.insert(items, tostring(value)) + end + end + if #items > 0 then + return table.concat(items, entry.sep or ";") + end + end + return nil + end + return _get_csharp_value(target, entry.lua_key, entry.default) +end + +function _collect_project_attributes(target, context, registry_entries) + local attrs = {} + for _, entry in ipairs(registry_entries) do + if entry.kind == "project_attribute" then + if not entry.when or entry.when(context) then + local value = _resolve_registry_value(entry, target, context) + if value ~= nil and value ~= "" then + attrs[entry.attr] = value + end + end + end + end + return attrs +end + +function _collect_property_entries(target, context, registry_entries) + local entries = {} + for _, entry in ipairs(registry_entries) do + if entry.kind == "property" then + if not entry.when or entry.when(context) then + local value = _resolve_registry_value(entry, target, context) + if value ~= nil and value ~= "" then + table.insert(entries, {xml = entry.xml, value = value}) + end + end + end + end + return entries +end + +function _normalize_item_entry(item, default_xml) + if type(item) == "string" then + return {xml = default_xml, attrs = {Include = item}} + elseif type(item) ~= "table" then + return nil + end + local xml = item.xml or default_xml + if not xml or #tostring(xml) == 0 then + return nil + end + local attrs = item.attrs + if type(attrs) ~= "table" then + attrs = {} + for key, value in pairs(item) do + if type(key) == "string" and key ~= "xml" and key ~= "value" and key ~= "attrs" then + attrs[key] = value + end + end + end + return {xml = xml, attrs = attrs, value = item.value} +end + +function _collect_item_groups(context, registry_entries) + local groups = {} + local groupmap = {} + function _group(name) + local g = groupmap[name] + if not g then + g = {name = name, items = {}} + groupmap[name] = g + table.insert(groups, g) + end + return g + end + for _, entry in ipairs(registry_entries) do + if entry.kind == "item" then + if not entry.when or entry.when(context) then + for _, item in ipairs(table.wrap(entry.resolve_items and entry.resolve_items(context) or {})) do + local normalized = _normalize_item_entry(item, entry.xml) + if normalized then + table.insert(_group(entry.group or entry.xml).items, normalized) + end + end + end + end + end + return groups +end + +function _is_valid_property_name(name) + return type(name) == "string" and name:match("^[A-Za-z_][A-Za-z0-9_.-]*$") ~= nil +end + +function _add_custom_property(entries, name, value) + if not _is_valid_property_name(name) then + return + end + if value == nil then + return + end + if type(value) == "table" then + local values = {} + for _, v in ipairs(value) do + if v ~= nil and v ~= "" then + table.insert(values, tostring(v)) + end + end + if #values == 0 then + return + end + value = table.concat(values, ";") + else + value = tostring(value) + end + if #value == 0 then + return + end + table.insert(entries, {xml = name, value = value}) +end + +function _add_custom_properties_from_item(entries, item) + if type(item) == "string" then + local name, value = item:match("^%s*([^=]+)%s*=(.*)$") + if name then + _add_custom_property(entries, name:trim(), value) + end + return + end + if type(item) ~= "table" then + return + end + if item.name then + _add_custom_property(entries, tostring(item.name), item.value) + return + end + local keys = {} + for k in pairs(item) do + if type(k) == "string" then + table.insert(keys, k) + end + end + table.sort(keys) + for _, key in ipairs(keys) do + _add_custom_property(entries, key, item[key]) + end +end + +function _collect_custom_property_entries(target) + local entries = {} + for _, item in ipairs(table.wrap(target:values("csharp.properties"))) do + _add_custom_properties_from_item(entries, item) + end + return entries +end + +function _render_property_group(lines, entries) + if #entries == 0 then + return + end + table.insert(lines, " ") + for _, entry in ipairs(entries) do + table.insert(lines, string.format(" <%s>%s", entry.xml, _xml_escape(entry.value), entry.xml)) + end + table.insert(lines, " ") +end + +function _render_item_groups(lines, item_groups) + for _, group in ipairs(item_groups) do + if #group.items > 0 then + table.insert(lines, " ") + for _, item in ipairs(group.items) do + local attrs = _format_attributes(item.attrs) + if item.value ~= nil and item.value ~= "" then + table.insert(lines, string.format(" <%s%s>%s", item.xml, attrs, _xml_escape(item.value), item.xml)) + else + table.insert(lines, string.format(" <%s%s />", item.xml, attrs)) + end + end + table.insert(lines, " ") + end + end +end + +function main(target, csprojfile, opt) + opt = opt or {} + + local csprojdir = path.directory(csprojfile) + local context = { + target = target, + csprojfile = csprojfile, + csprojdir = csprojdir, + opt = opt + } + + local property_registry_entries = csharp_properties() + local item_registry_entries = csharp_itemgroups() + + local project_attributes = _collect_project_attributes(target, context, property_registry_entries) + local property_entries = _collect_property_entries(target, context, property_registry_entries) + local custom_property_entries = _collect_custom_property_entries(target) + table.join2(property_entries, custom_property_entries) + + local item_groups = _collect_item_groups(context, item_registry_entries) + local lines = {} + + table.insert(lines, string.format("", _format_attributes(project_attributes))) + _render_property_group(lines, property_entries) + _render_item_groups(lines, item_groups) + table.insert(lines, "") + + local content = table.concat(lines, "\n") .. "\n" + + os.mkdir(csprojdir) + local oldcontent = nil + if os.isfile(csprojfile) then + oldcontent = io.readfile(csprojfile) + end + if oldcontent ~= content then + io.writefile(csprojfile, content) + end +end diff --git a/xmake/rules/csharp/modules/itemgroups.lua b/xmake/rules/csharp/modules/itemgroups.lua new file mode 100644 index 000000000..6d105fd45 --- /dev/null +++ b/xmake/rules/csharp/modules/itemgroups.lua @@ -0,0 +1,166 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author JassJam +-- @file itemsgroups.lua +-- + +local function _normalize_relative(fromdir, targetpath) + local relpath = path.relative(targetpath, fromdir) or targetpath + if os.host() == "windows" then + relpath = relpath:gsub("\\", "/") + end + return relpath +end + +local function _collect_cs_sourcefiles(context) + local csfiles = {} + for _, sourcefile in ipairs(context.target:sourcefiles()) do + if path.extension(sourcefile):lower() == ".cs" then + local sourceabs = path.is_absolute(sourcefile) and sourcefile or path.absolute(sourcefile, os.projectdir()) + table.insert(csfiles, _normalize_relative(context.csprojdir, sourceabs)) + end + end + table.sort(csfiles) + return table.unique(csfiles) +end + +local function _collect_project_references(context) + if context.opt.skip_deps then + return {} + end + local references = {} + for _, depname in ipairs(table.wrap(context.target:get("deps"))) do + local dep = context.target:dep(depname) + if dep and context.opt.is_csharp_target and context.opt.is_csharp_target(dep) then + local depcsproj = context.opt.find_or_generate_csproj and context.opt.find_or_generate_csproj(dep) + if depcsproj then + table.insert(references, _normalize_relative(context.csprojdir, depcsproj)) + end + end + end + table.sort(references) + return table.unique(references) +end + +local function _get_nuget_info(pkg) + local requirestr = pkg:requirestr() or "" + local splitinfo = requirestr:trim():split("%s+") + if #splitinfo == 0 then + return nil + end + + local pkgname = splitinfo[1] + if pkgname:find("::", 1, true) then + pkgname = pkgname:split("::", {plain = true}) + pkgname = pkgname[#pkgname] + end + local pkgname_raw = pkgname:match("(.-)%[.*%]$") + if pkgname_raw and #pkgname_raw > 0 then + pkgname = pkgname_raw + end + if not pkgname or #pkgname == 0 then + return nil + end + + local version + local versionobj = pkg:version() + if versionobj then + version = tostring(versionobj) + end + if not version and #splitinfo > 1 then + local require_version = table.concat(table.slice(splitinfo, 2), " ") + if require_version ~= "latest" then + version = require_version + end + end + return pkgname, version +end + +local function _collect_nuget_references(context) + local versions = {} + for _, pkg in ipairs(context.target:orderpkgs()) do + local namespace = pkg:namespace() + local requirestr = pkg:requirestr() or "" + if namespace == "nuget" or requirestr:startswith("nuget::") then + local pkgname, version = _get_nuget_info(pkg) + if pkgname then + if version or versions[pkgname] == nil then + versions[pkgname] = version or false + end + end + end + end + + local references = {} + for pkgname, version in pairs(versions) do + table.insert(references, {name = pkgname, version = version or nil}) + end + table.sort(references, function (a, b) return a.name < b.name end) + return references +end + +function main() + local entries = {} + local function register(entry) + table.insert(entries, entry) + end + + register({ + kind = "item", + group = "compile", + xml = "Compile", + resolve_items = function (context) + local items = {} + for _, sourcefile in ipairs(_collect_cs_sourcefiles(context)) do + table.insert(items, {attrs = {Include = sourcefile}}) + end + return items + end + }) + + register({ + kind = "item", + group = "project_reference", + xml = "ProjectReference", + resolve_items = function (context) + local items = {} + for _, reffile in ipairs(_collect_project_references(context)) do + table.insert(items, {attrs = {Include = reffile}}) + end + return items + end + }) + + register({ + kind = "item", + group = "package_reference", + xml = "PackageReference", + resolve_items = function (context) + local items = {} + for _, pkginfo in ipairs(_collect_nuget_references(context)) do + local attrs = {Include = pkginfo.name} + if pkginfo.version then + attrs.Version = pkginfo.version + end + table.insert(items, {attrs = attrs}) + end + return items + end + }) + + return entries +end diff --git a/xmake/rules/csharp/modules/properties.lua b/xmake/rules/csharp/modules/properties.lua new file mode 100644 index 000000000..b8d30f1e9 --- /dev/null +++ b/xmake/rules/csharp/modules/properties.lua @@ -0,0 +1,307 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author JassJam +-- @file properties.lua +-- + +function _has_target_frameworks(context) + return #table.wrap(context.target:values("csharp.target_frameworks")) > 0 +end + +local _default_target_framework_cached = {} + +function _first(value) + if type(value) == "table" then + return value[1] + end + return value +end + +function _get_target_value(target, name) + return _first(target:values(name)) +end + +function _collect_strings(result, value) + if value == nil then + return + end + if type(value) == "table" then + for _, item in ipairs(value) do + _collect_strings(result, item) + end + else + local sval = tostring(value) + if #sval > 0 then + table.insert(result, sval) + end + end +end + +function _extract_define_symbol(define) + define = tostring(define):trim() + if #define == 0 then + return nil + end + local symbol = define:split("=", {plain = true})[1] + if not symbol then + return nil + end + symbol = symbol:trim() + if symbol:match("^[A-Za-z_][A-Za-z0-9_]*$") then + return symbol + end + return nil +end + +function _resolve_define_constants(context) + local target = context.target + local constants = {} + + _collect_strings(constants, target:get("defines")) + local opt_defines = target:get_from("defines", "option::*") + if opt_defines then + _collect_strings(constants, opt_defines) + end + + local symbols = {} + for _, define in ipairs(constants) do + local symbol = _extract_define_symbol(define) + if symbol then + table.insert(symbols, symbol) + end + end + symbols = table.unique(symbols) + if #symbols > 0 then + return table.concat(symbols, ";") + end +end + +function _get_default_target_framework(context) + local dotnet = _first(context.target:get("toolset.cs")) or "dotnet" + dotnet = tostring(dotnet) + local cached = _default_target_framework_cached[dotnet] + if cached ~= nil then + return cached + end + + local major = nil + local sdks = try { function () + return os.iorunv(dotnet, {"--list-sdks"}) + end } + if sdks then + for line in sdks:gmatch("[^\r\n]+") do + local line_major = tonumber(line:match("^%s*(%d+)%.%d+%.%d+")) + if line_major and (not major or line_major > major) then + major = line_major + end + end + end + if not major then + local version = try { function () + return os.iorunv(dotnet, {"--version"}) + end } + if version then + major = tonumber(version:match("^%s*(%d+)")) + end + end + + local target_framework = major and ("net" .. tostring(major) .. ".0") or "net8.0" + _default_target_framework_cached[dotnet] = target_framework + return target_framework +end + +function _resolve_target_framework(context) + local target_framework = _get_target_value(context.target, "csharp.target_framework") + if target_framework ~= nil and #tostring(target_framework) > 0 then + return target_framework + end + return _get_default_target_framework(context) +end + +function _resolve_assembly_name(context) + local basename = context.target:basename() + if basename ~= nil and #tostring(basename) > 0 then + return basename + end +end + +function _resolve_optimize(context) + local optimize = _first(context.target:get("optimize")) + if optimize ~= nil then + return optimize == "none" and "false" or "true" + end +end + +function _resolve_debug_symbols(context) + local symbols = _first(context.target:get("symbols")) + if symbols ~= nil then + return symbols == "none" and "false" or "true" + end +end + +function _resolve_debug_type(context) + local symbols = _first(context.target:get("symbols")) + if symbols and symbols ~= "none" then + return "portable" + end +end + +function _resolve_platform_target(context) + local arch = (context.target:arch() or ""):lower() + local mapping = { + x86_64 = "x64", + amd64 = "x64", + x64 = "x64", + i386 = "x86", + x86 = "x86", + arm64 = "arm64", + arm = "arm", + armv7 = "arm" + } + return mapping[arch] +end + +function _resolve_warning_level(context) + local warnings = _first(context.target:get("warnings")) + local mapping = { + none = "0", + less = "2", + more = "3", + all = "4", + allextra = "4", + everything = "4", + error = "4" + } + return warnings and mapping[warnings] +end + +function _resolve_treat_warnings_as_errors(context) + local warnings = _first(context.target:get("warnings")) + if warnings == "error" then + return "true" + end +end + +function _register_property(register, suffix, xml, default, extra) + local entry = table.join({ + kind = "property", + xml = xml, + lua_key = "csharp." .. suffix, + default = default + }, extra or {}) + register(entry) +end + +function _register_list_property(register, suffix, xml, extra) + local entry = table.join({ + kind = "property", + xml = xml, + lua_key = "csharp." .. suffix, + value_type = "list", + sep = ";" + }, extra or {}) + register(entry) +end + +function main() + local entries = {} + function register(entry) + table.insert(entries, entry) + end + + register({kind = "project_attribute", attr = "Sdk", lua_key = "csharp.sdk", default = "Microsoft.NET.Sdk"}) + register({kind = "property", xml = "OutputType", resolve = function (context) + return context.target:is_binary() and "Exe" or "Library" + end}) + _register_list_property(register, "target_frameworks", "TargetFrameworks", {when = _has_target_frameworks}) + register({kind = "property", xml = "TargetFramework", resolve = _resolve_target_framework, when = function (context) + return not _has_target_frameworks(context) + end}) + + _register_property(register, "implicit_usings", "ImplicitUsings", "enable") + _register_property(register, "nullable", "Nullable", "enable") + _register_property(register, "lang_version", "LangVersion") + _register_property(register, "enable_default_compile_items", "EnableDefaultCompileItems", "false") + _register_property(register, "enable_default_embedded_resource_items", "EnableDefaultEmbeddedResourceItems") + _register_property(register, "enable_default_none_items", "EnableDefaultNoneItems") + _register_property(register, "root_namespace", "RootNamespace") + register({kind = "property", xml = "AssemblyName", resolve = _resolve_assembly_name}) + _register_property(register, "generate_assembly_info", "GenerateAssemblyInfo") + _register_property(register, "deterministic", "Deterministic") + register({kind = "property", xml = "Optimize", resolve = _resolve_optimize}) + register({kind = "property", xml = "PlatformTarget", resolve = _resolve_platform_target}) + _register_property(register, "prefer_32bit", "Prefer32Bit") + _register_property(register, "allow_unsafe_blocks", "AllowUnsafeBlocks") + _register_property(register, "check_for_overflow_underflow", "CheckForOverflowUnderflow") + register({kind = "property", xml = "WarningLevel", resolve = _resolve_warning_level}) + _register_property(register, "analysis_level", "AnalysisLevel") + _register_property(register, "enable_net_analyzers", "EnableNETAnalyzers") + _register_property(register, "enforce_code_style_in_build", "EnforceCodeStyleInBuild") + register({kind = "property", xml = "TreatWarningsAsErrors", resolve = _resolve_treat_warnings_as_errors}) + _register_list_property(register, "warnings_as_errors", "WarningsAsErrors") + _register_list_property(register, "warnings_not_as_errors", "WarningsNotAsErrors") + register({kind = "property", xml = "DefineConstants", resolve = _resolve_define_constants}) + _register_property(register, "error_log", "ErrorLog") + register({kind = "property", xml = "DebugType", resolve = _resolve_debug_type}) + register({kind = "property", xml = "DebugSymbols", resolve = _resolve_debug_symbols}) + _register_property(register, "generate_documentation_file", "GenerateDocumentationFile") + _register_property(register, "documentation_file", "DocumentationFile") + + _register_property(register, "runtime_identifier", "RuntimeIdentifier") + _register_list_property(register, "runtime_identifiers", "RuntimeIdentifiers") + _register_property(register, "self_contained", "SelfContained") + _register_property(register, "use_app_host", "UseAppHost") + _register_property(register, "roll_forward", "RollForward") + _register_property(register, "publish_single_file", "PublishSingleFile") + _register_property(register, "publish_trimmed", "PublishTrimmed") + _register_property(register, "trim_mode", "TrimMode") + _register_property(register, "publish_ready_to_run", "PublishReadyToRun") + _register_property(register, "invariant_globalization", "InvariantGlobalization") + _register_property(register, "include_native_libraries_for_self_extract", "IncludeNativeLibrariesForSelfExtract") + _register_property(register, "enable_compression_in_single_file", "EnableCompressionInSingleFile") + _register_property(register, "publish_aot", "PublishAot") + _register_property(register, "strip_symbols", "StripSymbols") + _register_property(register, "enable_trim_analyzer", "EnableTrimAnalyzer") + _register_property(register, "json_serializer_is_reflection_enabled_by_default", "JsonSerializerIsReflectionEnabledByDefault") + _register_list_property(register, "satellite_resource_languages", "SatelliteResourceLanguages") + + _register_property(register, "version", "Version") + _register_property(register, "assembly_version", "AssemblyVersion") + _register_property(register, "file_version", "FileVersion") + _register_property(register, "informational_version", "InformationalVersion") + _register_property(register, "package_id", "PackageId") + _register_property(register, "authors", "Authors") + _register_property(register, "company", "Company") + _register_property(register, "product", "Product") + _register_property(register, "description", "Description") + _register_property(register, "copyright", "Copyright") + _register_property(register, "repository_url", "RepositoryUrl") + _register_property(register, "repository_type", "RepositoryType") + _register_property(register, "package_license_expression", "PackageLicenseExpression") + _register_property(register, "package_project_url", "PackageProjectUrl") + _register_property(register, "neutral_language", "NeutralLanguage") + _register_property(register, "enable_preview_features", "EnablePreviewFeatures") + + _register_property(register, "generate_runtime_configuration_files", "GenerateRuntimeConfigurationFiles") + _register_property(register, "copy_local_lock_file_assemblies", "CopyLocalLockFileAssemblies") + _register_property(register, "append_target_framework_to_output_path", "AppendTargetFrameworkToOutputPath", "false") + _register_property(register, "append_runtime_identifier_to_output_path", "AppendRuntimeIdentifierToOutputPath", "false") + _register_property(register, "produce_reference_assembly", "ProduceReferenceAssembly") + _register_property(register, "disable_implicit_framework_references", "DisableImplicitFrameworkReferences") + _register_property(register, "generate_target_framework_attribute", "GenerateTargetFrameworkAttribute") + return entries +end diff --git a/xmake/rules/csharp/xmake.lua b/xmake/rules/csharp/xmake.lua index 5d358e099..b5e76dfa9 100644 --- a/xmake/rules/csharp/xmake.lua +++ b/xmake/rules/csharp/xmake.lua @@ -24,10 +24,87 @@ -- target("app") -- set_kind("binary") -- or "shared" -- add_rules("csharp") --- add_files("src/*.cs", "src/app.csproj") +-- add_files("src/*.cs") -- --- -- optional: override runtime identifier (arch-specific) for self-contained publish (e.g. "win-x64", "linux-x64", "osx-x64", "osx-arm64") --- -- add_values("csharp.runtime_identifier", "win-x64") +-- -- optional: if a .csproj is provided, xmake uses it directly. +-- -- otherwise xmake auto-generates one in .xmake/... for dotnet build/publish. +-- -- add_files("src/app.csproj") +-- +-- -- add_values("csharp.", ) -- use one the properties below +-- -- add_values("csharp.properties", "AnotherProperty=Value") -- declare a custom property +-- +-- -- mapped csharp properties (lua key => generated xml): +-- -- https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-target +-- -- csharp.sdk => (project attribute) (defaults to "Microsoft.NET.Sdk") +-- -- csharp.target_frameworks => (list, ';' separated) +-- -- csharp.target_framework => (defaults to latest installed dotnet sdk major, e.g. net8.0) +-- -- csharp.implicit_usings => +-- -- csharp.nullable => +-- -- csharp.lang_version => +-- -- csharp.enable_default_compile_items => +-- -- csharp.enable_default_embedded_resource_items => +-- -- csharp.enable_default_none_items => +-- -- csharp.root_namespace => +-- -- default/derived: set_basename(...) => +-- -- csharp.generate_assembly_info => +-- -- csharp.deterministic => +-- -- default/derived: set_optimize(...) => +-- -- default/derived: get_plat()/get_arch() => +-- -- csharp.prefer_32bit => +-- -- csharp.allow_unsafe_blocks => +-- -- csharp.check_for_overflow_underflow => +-- -- default/derived: set_warnings(...) => +-- -- csharp.analysis_level => +-- -- csharp.enable_net_analyzers => +-- -- csharp.enforce_code_style_in_build => +-- -- default/derived: set_warnings("error") => true +-- -- csharp.warnings_as_errors => (list, ';' separated) +-- -- csharp.warnings_not_as_errors => (list, ';' separated) +-- -- default/derived: add_defines(...) => +-- -- csharp.error_log => +-- -- default/derived: set_symbols(...) => / +-- -- csharp.generate_documentation_file => +-- -- csharp.documentation_file => +-- -- csharp.runtime_identifier => +-- -- csharp.runtime_identifiers => (list, ';' separated) +-- -- csharp.self_contained => +-- -- csharp.use_app_host => +-- -- csharp.roll_forward => +-- -- csharp.publish_single_file => +-- -- csharp.publish_trimmed => +-- -- csharp.trim_mode => +-- -- csharp.publish_ready_to_run => +-- -- csharp.invariant_globalization => +-- -- csharp.include_native_libraries_for_self_extract => +-- -- csharp.enable_compression_in_single_file => +-- -- csharp.publish_aot => +-- -- csharp.strip_symbols => +-- -- csharp.enable_trim_analyzer => +-- -- csharp.json_serializer_is_reflection_enabled_by_default => +-- -- csharp.satellite_resource_languages => (list, ';' separated) +-- -- csharp.version => +-- -- csharp.assembly_version => +-- -- csharp.file_version => +-- -- csharp.informational_version => +-- -- csharp.package_id => +-- -- csharp.authors => +-- -- csharp.company => +-- -- csharp.product => +-- -- csharp.description => +-- -- csharp.copyright => +-- -- csharp.repository_url => +-- -- csharp.repository_type => +-- -- csharp.package_license_expression => +-- -- csharp.package_project_url => +-- -- csharp.neutral_language => +-- -- csharp.enable_preview_features => +-- -- csharp.generate_runtime_configuration_files => +-- -- csharp.copy_local_lock_file_assemblies => +-- -- csharp.append_target_framework_to_output_path => (default: false) +-- -- csharp.append_runtime_identifier_to_output_path => (default: false) +-- -- csharp.produce_reference_assembly => +-- -- csharp.disable_implicit_framework_references => +-- -- csharp.generate_target_framework_attribute => -- @endcode -- rule("csharp") -- cgit v1.3.1