summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-03-14 00:04:01 +0800
committerruki <[email protected]>2026-03-14 00:11:43 +0800
commita86bde866d5f65d5fbd31f1474190dcc40aa2876 (patch)
treea043c2be4830b300a59543f8d10bcfddced70f4f
parent4b56123d797578f1abec0c3d507282d9e5bc8f3b (diff)
improve csharp support
-rw-r--r--xmake/modules/core/tools/dotnet.lua88
-rw-r--r--xmake/modules/core/tools/dotnet/has_flags.lua50
-rw-r--r--xmake/modules/detect/sdks/find_dotnet.lua134
-rw-r--r--xmake/modules/detect/tools/find_dotnet.lua53
-rw-r--r--xmake/toolchains/dotnet/xmake.lua60
5 files changed, 342 insertions, 43 deletions
diff --git a/xmake/modules/core/tools/dotnet.lua b/xmake/modules/core/tools/dotnet.lua
new file mode 100644
index 000000000..4cc96e317
--- /dev/null
+++ b/xmake/modules/core/tools/dotnet.lua
@@ -0,0 +1,88 @@
+--!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 ruki
+-- @file dotnet.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.project.config")
+import("core.project.project")
+import("core.language.language")
+
+-- init it
+function init(self)
+end
+
+-- make the define flag
+function nf_define(self, macro)
+ return {"-p:DefineConstants=" .. macro}
+end
+
+-- make the optimize flag
+function nf_optimize(self, level)
+ local maps = {
+ none = "-p:Optimize=false"
+ , fast = "-p:Optimize=true"
+ , faster = "-p:Optimize=true"
+ , fastest = "-p:Optimize=true"
+ , smallest = "-p:Optimize=true"
+ , aggressive = "-p:Optimize=true"
+ }
+ return maps[level]
+end
+
+-- make the symbol flag
+function nf_symbol(self, level)
+ local maps = {
+ debug = {"-p:DebugType=full", "-p:DebugSymbols=true"}
+ , hidden = {"-p:DebugType=pdbonly", "-p:DebugSymbols=true"}
+ }
+ return maps[level]
+end
+
+-- make the warning flag
+function nf_warning(self, level)
+ local maps = {
+ none = "-p:WarningLevel=0"
+ , less = "-p:WarningLevel=1"
+ , more = "-p:WarningLevel=3"
+ , all = "-p:WarningLevel=5"
+ , allextra = "-p:WarningLevel=9999"
+ , error = {"-p:WarningLevel=5", "-p:TreatWarningsAsErrors=true"}
+ }
+ return maps[level]
+end
+
+-- make the build arguments list
+function buildargv(self, sourcefiles, targetkind, targetfile, flags)
+ local argv = {"build"}
+ if flags then
+ table.join2(argv, flags)
+ end
+ table.insert(argv, "--output")
+ table.insert(argv, path.directory(targetfile))
+ table.join2(argv, sourcefiles)
+ return self:program(), argv
+end
+
+-- build the target file
+function build(self, sourcefiles, targetkind, targetfile, flags)
+ os.mkdir(path.directory(targetfile))
+ local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags)
+ os.runv(program, argv, {envs = self:runenvs()})
+end
diff --git a/xmake/modules/core/tools/dotnet/has_flags.lua b/xmake/modules/core/tools/dotnet/has_flags.lua
new file mode 100644
index 000000000..eaffa7e88
--- /dev/null
+++ b/xmake/modules/core/tools/dotnet/has_flags.lua
@@ -0,0 +1,50 @@
+--!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 ruki
+-- @file has_flags.lua
+--
+
+-- attempt to check it from known flags
+function _check_from_knownargs(flags, opt)
+ local flag = flags[1]
+ -- dotnet MSBuild properties
+ if flag:startswith("-p:") or flag:startswith("/p:") then
+ return true
+ end
+ -- dotnet CLI options
+ if flag:startswith("--") then
+ return true
+ end
+ -- common csflags patterns
+ if flag:startswith("-") or flag:startswith("/") then
+ return true
+ end
+end
+
+-- has_flags(flags)?
+--
+-- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[cs|csld|cssh]"}
+--
+-- @return true or false
+--
+function main(flags, opt)
+ opt = opt or {}
+ if _check_from_knownargs(flags, opt) then
+ return true
+ end
+ return false
+end
diff --git a/xmake/modules/detect/sdks/find_dotnet.lua b/xmake/modules/detect/sdks/find_dotnet.lua
index 2dfd2a916..3430d2626 100644
--- a/xmake/modules/detect/sdks/find_dotnet.lua
+++ b/xmake/modules/detect/sdks/find_dotnet.lua
@@ -20,16 +20,60 @@
-- imports
import("lib.detect.find_file")
+import("lib.detect.find_tool")
import("core.tool.toolchain")
import("core.base.option")
import("core.base.global")
import("core.project.config")
import("core.cache.detectcache")
--- find dotnet directory
-function _find_sdkdir(sdkdir)
+-- find dotnet sdk info from dotnet cli
+function _find_dotnet_cli()
+ local dotnet = find_tool("dotnet", {version = true})
+ if not dotnet then
+ return nil
+ end
+
+ local result = {program = dotnet.program, version = dotnet.version}
+
+ -- get sdk list, e.g. "8.0.100 [/usr/share/dotnet/sdk]"
+ local sdklist = try { function () return os.iorunv(dotnet.program, {"--list-sdks"}) end }
+ if sdklist then
+ local sdks = {}
+ for _, line in ipairs(sdklist:split("\n", {plain = true})) do
+ line = line:trim()
+ local ver, dir = line:match("^(%S+)%s+%[(.-)%]")
+ if ver and dir then
+ table.insert(sdks, {version = ver, directory = path.join(dir, ver)})
+ end
+ end
+ if #sdks > 0 then
+ result.sdks = sdks
+ result.sdkdir = sdks[#sdks].directory
+ result.sdkver = sdks[#sdks].version
+ end
+ end
+
+ -- get runtime list, e.g. "Microsoft.NETCore.App 8.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App]"
+ local runtimelist = try { function () return os.iorunv(dotnet.program, {"--list-runtimes"}) end }
+ if runtimelist then
+ local runtimes = {}
+ for _, line in ipairs(runtimelist:split("\n", {plain = true})) do
+ line = line:trim()
+ local name, ver = line:match("^(%S+)%s+(%S+)%s+%[")
+ if name and ver then
+ table.insert(runtimes, {name = name, version = ver})
+ end
+ end
+ if #runtimes > 0 then
+ result.runtimes = runtimes
+ end
+ end
+ return result
+end
- -- get sdk directory from vcvars
+-- find .NET Framework SDK directory from MSVC (Windows only)
+function _find_netfxsdk(sdkdir)
if not sdkdir then
local msvc = toolchain.load("msvc")
if msvc and msvc:check() then
@@ -42,55 +86,40 @@ function _find_sdkdir(sdkdir)
end
end
end
- return sdkdir
-end
-
--- find dotnet toolchains
-function _find_dotnet(sdkdir, sdkver)
-
- -- find dotnet directory
- sdkdir = _find_sdkdir(sdkdir)
if not sdkdir or not os.isdir(sdkdir) then
return nil
end
-- get sdk version
- if not sdkver then
- local vers = {}
- for _, dir in ipairs(os.dirs(path.join(sdkdir, "*", "Include"))) do
- table.insert(vers, path.filename(path.directory(dir)))
- end
- for _, ver in ipairs(vers) do
- if os.isdir(path.join(sdkdir, ver, "Lib", "um")) and os.isdir(path.join(sdkdir, ver, "Include", "um")) then
- sdkver = ver
- break
- end
+ local sdkver
+ local vers = {}
+ for _, dir in ipairs(os.dirs(path.join(sdkdir, "*", "Include"))) do
+ table.insert(vers, path.filename(path.directory(dir)))
+ end
+ for _, ver in ipairs(vers) do
+ if os.isdir(path.join(sdkdir, ver, "Lib", "um")) and os.isdir(path.join(sdkdir, ver, "Include", "um")) then
+ sdkver = ver
+ break
end
end
if not sdkver then
return nil
end
-
- -- get the lib directory
- local libdir = path.join(sdkdir, sdkver, "Lib")
-
- -- get the include directory
- local includedir = path.join(sdkdir, sdkver, "Include")
-
- -- get toolchains
- return {sdkdir = sdkdir, libdir = libdir, includedir = includedir, sdkver = sdkver}
+ return {sdkdir = sdkdir, sdkver = sdkver,
+ libdir = path.join(sdkdir, sdkver, "Lib"),
+ includedir = path.join(sdkdir, sdkver, "Include")}
end
--- find dotnet toolchains
+-- find dotnet sdk
--
-- @param sdkdir the dotnet directory
--- @param opt the argument options, e.g. {verbose = true, force = false, version = "5.9.1"}
+-- @param opt the argument options, e.g. {verbose = true, force = false}
--
--- @return the dotnet toolchains. e.g. {sdkver = ..., sdkdir = ..., bindir = .., libdir = ..., includedir = ..., .. }
+-- @return the dotnet sdk info, e.g. {program = ..., version = ..., sdkver = ..., sdkdir = ..., sdks = {...}, runtimes = {...}}
--
-- @code
--
--- local toolchains = find_dotnet("~/dotnet")
+-- local dotnet = find_dotnet()
--
-- @endcode
--
@@ -106,24 +135,43 @@ function main(sdkdir, opt)
return cacheinfo.dotnet
end
- -- find dotnet
- local dotnet = _find_dotnet(sdkdir or config.get("dotnet") or global.get("dotnet"), opt.version or config.get("dotnet_sdkver"))
- if dotnet then
+ -- find dotnet cli sdk
+ local dotnet = _find_dotnet_cli()
+ -- find .NET Framework SDK on Windows
+ if is_host("windows") then
+ local netfxsdk = _find_netfxsdk(sdkdir or config.get("dotnet") or global.get("dotnet"))
+ if netfxsdk then
+ if dotnet then
+ dotnet.netfxsdk = netfxsdk
+ else
+ dotnet = netfxsdk
+ end
+ end
+ end
+
+ if dotnet then
-- save to config
- config.set("dotnet", dotnet.sdkdir, {force = true, readonly = true})
- config.set("dotnet_sdkver", dotnet.sdkver, {force = true, readonly = true})
+ if dotnet.sdkdir then
+ config.set("dotnet", dotnet.sdkdir, {force = true, readonly = true})
+ end
+ if dotnet.sdkver then
+ config.set("dotnet_sdkver", dotnet.sdkver, {force = true, readonly = true})
+ end
-- trace
if opt.verbose or option.get("verbose") then
- cprint("checking for .Net SDK directory ... ${color.success}%s", dotnet.sdkdir)
- cprint("checking for .Net SDK version ... ${color.success}%s", dotnet.sdkver)
+ if dotnet.version then
+ cprint("checking for .NET SDK version ... ${color.success}%s", dotnet.version)
+ end
+ if dotnet.sdkdir then
+ cprint("checking for .NET SDK directory ... ${color.success}%s", dotnet.sdkdir)
+ end
end
else
-
-- trace
if opt.verbose or option.get("verbose") then
- cprint("checking for .Net SDK directory ... ${color.nothing}${text.nothing}")
+ cprint("checking for .NET SDK directory ... ${color.nothing}${text.nothing}")
end
end
diff --git a/xmake/modules/detect/tools/find_dotnet.lua b/xmake/modules/detect/tools/find_dotnet.lua
new file mode 100644
index 000000000..ac17979ec
--- /dev/null
+++ b/xmake/modules/detect/tools/find_dotnet.lua
@@ -0,0 +1,53 @@
+--!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 ruki
+-- @file find_dotnet.lua
+--
+
+-- imports
+import("lib.detect.find_program")
+import("lib.detect.find_programver")
+
+-- find dotnet
+--
+-- @param opt the argument options, e.g. {version = true}
+--
+-- @return program, version
+--
+-- @code
+--
+-- local dotnet = find_dotnet()
+--
+-- @endcode
+--
+function main(opt)
+
+ -- init options
+ opt = opt or {}
+ opt.check = opt.check or "--version"
+ opt.command = opt.command or "--version"
+
+ -- find program
+ local program = find_program(opt.program or "dotnet", opt)
+
+ -- find program version
+ local version = nil
+ if program and opt and opt.version then
+ version = find_programver(program, opt)
+ end
+ return program, version
+end
diff --git a/xmake/toolchains/dotnet/xmake.lua b/xmake/toolchains/dotnet/xmake.lua
new file mode 100644
index 000000000..9c1fe40c3
--- /dev/null
+++ b/xmake/toolchains/dotnet/xmake.lua
@@ -0,0 +1,60 @@
+--!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 ruki
+-- @file xmake.lua
+--
+
+toolchain("dotnet")
+ set_kind("standalone")
+ set_homepage("https://dotnet.microsoft.com/")
+ set_description(".NET SDK Toolchain")
+
+ set_toolset("cs", "dotnet")
+ set_toolset("csld", "dotnet")
+ set_toolset("cssh", "dotnet")
+
+ on_check(function (toolchain)
+ import("lib.detect.find_tool")
+ import("detect.sdks.find_dotnet")
+
+ -- find dotnet program
+ local dotnet = find_tool("dotnet", {version = true})
+ if not dotnet then
+ return false
+ end
+ toolchain:config_set("dotnet", dotnet.program)
+ toolchain:config_set("dotnet_version", dotnet.version)
+
+ -- find dotnet sdk info
+ local sdkinfo = find_dotnet()
+ if sdkinfo then
+ toolchain:config_set("sdkinfo", sdkinfo)
+ end
+ return true
+ end)
+
+ on_load(function (toolchain)
+ local dotnet = toolchain:config("dotnet") or "dotnet"
+ toolchain:set("toolset", "cs", dotnet)
+ toolchain:set("toolset", "csld", dotnet)
+ toolchain:set("toolset", "cssh", dotnet)
+
+ -- set default environment variables
+ toolchain:add("runenvs", "DOTNET_NOLOGO", "1")
+ toolchain:add("runenvs", "DOTNET_CLI_TELEMETRY_OPTOUT", "1")
+ toolchain:add("runenvs", "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "1")
+ end)