diff options
| author | ruki <[email protected]> | 2026-03-14 23:17:32 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-03-14 23:17:32 +0800 |
| commit | 7fa59f32b5c88c655d83a83bb05e3eb9680e5004 (patch) | |
| tree | 3d606e54e6d581bb8025e08c32fdecd523ada791 | |
| parent | 22976f06349a3af4b520ae5796ab20edc95bfe0c (diff) | |
improve csharp rules
| -rw-r--r-- | xmake/modules/core/tools/dotnet.lua | 57 | ||||
| -rw-r--r-- | xmake/rules/csharp/buildcmd.lua | 88 | ||||
| -rw-r--r-- | xmake/rules/csharp/install.lua | 81 | ||||
| -rw-r--r-- | xmake/rules/csharp/installcmd.lua | 59 | ||||
| -rw-r--r-- | xmake/rules/csharp/load.lua | 65 | ||||
| -rw-r--r-- | xmake/rules/csharp/modules/csharp_common.lua | 61 | ||||
| -rw-r--r-- | xmake/rules/csharp/xmake.lua | 126 |
7 files changed, 106 insertions, 431 deletions
diff --git a/xmake/modules/core/tools/dotnet.lua b/xmake/modules/core/tools/dotnet.lua index 4cc96e317..2647be1be 100644 --- a/xmake/modules/core/tools/dotnet.lua +++ b/xmake/modules/core/tools/dotnet.lua @@ -68,21 +68,66 @@ function nf_warning(self, level) return maps[level] end +-- get the .csproj file from source files +function _get_csprojfile(sourcefiles, opt) + local target = opt and opt.target + if target then + local csprojfile = target:data("csharp.csproj") + if csprojfile then + return csprojfile + end + end + -- find .csproj from source files + for _, sourcefile in ipairs(sourcefiles) do + if sourcefile:endswith(".csproj") then + return sourcefile + end + end +end + +-- get dotnet verbosity level +function _get_verbosity() + if option.get("diagnosis") then + return "diagnostic" + end + return "quiet" +end + +-- get build configuration from mode +function _get_configuration() + local mode = config.mode() or "release" + if mode:lower() == "debug" then + return "Debug" + end + return "Release" +end + -- make the build arguments list -function buildargv(self, sourcefiles, targetkind, targetfile, flags) +function buildargv(self, sourcefiles, targetkind, targetfile, flags, opt) local argv = {"build"} + + -- add .csproj file + local csprojfile = _get_csprojfile(sourcefiles, opt) + if csprojfile then + table.insert(argv, csprojfile) + end + + -- add common options + table.join2(argv, {"--nologo", "--configuration", _get_configuration(), "--verbosity", _get_verbosity()}) + + -- add output directory + table.join2(argv, {"--output", path.directory(targetfile)}) + + -- add flags 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) +function build(self, sourcefiles, targetkind, targetfile, flags, opt) os.mkdir(path.directory(targetfile)) - local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags) + local program, argv = buildargv(self, sourcefiles, targetkind, targetfile, flags, opt) os.runv(program, argv, {envs = self:runenvs()}) end diff --git a/xmake/rules/csharp/buildcmd.lua b/xmake/rules/csharp/buildcmd.lua deleted file mode 100644 index 614cc5a25..000000000 --- a/xmake/rules/csharp/buildcmd.lua +++ /dev/null @@ -1,88 +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 buildcmd.lua --- - -import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) - -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_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() - local command = target:is_binary() and "publish" or "build" - local argv = { - command, csprojfile, - "--nologo", - "--configuration", configuration, - "--verbosity", verbosity - } - - local targetdir = target:targetdir() - local targetdirabs - if targetdir then - targetdirabs = path.is_absolute(targetdir) and targetdir or path.absolute(targetdir, os.projectdir()) - table.join2(argv, {"--output", targetdirabs}) - end - - local rid = csharp_common.get_runtime_identifier(target) - if rid and target:is_binary() then - table.join2(argv, {"--runtime", rid}) - end - csharp_common.append_target_flags(target, argv) - - batchcmds:show_progress(opt.progress, "${color.build.target}building.csharp.$(mode) %s", target:name()) - if targetdirabs then - batchcmds:mkdir(targetdirabs) - end - batchcmds:vrunv(dotnet, argv, csharp_common.get_dotnet_runopt(csprojfile)) - - local targetfile = target:targetfile() - if targetfile then - 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/install.lua b/xmake/rules/csharp/install.lua index 32cc9e8e0..4d871e291 100644 --- a/xmake/rules/csharp/install.lua +++ b/xmake/rules/csharp/install.lua @@ -14,38 +14,28 @@ -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- --- @author JassJam +-- @author ruki -- @file install.lua -- +import("core.base.option") +import("core.project.config") +import("core.tool.compiler") import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) function main(target, opt) - local function _q(arg) - arg = tostring(arg) - if arg:find("[%s\"]") then - arg = "\"" .. arg:gsub("\"", "\\\"") .. "\"" - end - return arg - end - 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() - local install_path = target:installdir() - if target:is_binary() then - install_path = target:installdir("bin") - elseif target:is_static() or target:is_shared() then - install_path = target:installdir("lib") - end - if not install_path or #install_path == 0 then - return - end + -- get dotnet program from compiler toolchain + local compinst = compiler.load("cs", {target = target}) + local dotnet = compinst:program() - local install_abs = path.is_absolute(install_path) and install_path or path.absolute(install_path, os.projectdir()) - os.mkdir(install_abs) + local configuration = csharp_common.build_mode_to_configuration() + local verbosity = option.get("diagnosis") and "diagnostic" or "quiet" + + -- publish to a directory under target autogendir + local tmpdir = path.join(target:autogendir(), "publish") + os.mkdir(tmpdir) local rid = csharp_common.get_runtime_identifier(target) local argv = { @@ -53,43 +43,24 @@ function main(target, opt) "--nologo", "--configuration", configuration, "--verbosity", verbosity, - "--output", install_abs + "--output", tmpdir } if rid and target:is_binary() then table.join2(argv, {"--runtime", rid}) end - csharp_common.append_target_flags(target, argv) - - local runopt = csharp_common.get_dotnet_runopt(csprojfile) - if os.vrunv then - os.vrunv(dotnet, argv, runopt) - elseif os.runv then - os.runv(dotnet, argv, runopt) - elseif os.execv then - os.execv(dotnet, argv, runopt) - elseif os.vrun then - local cmd = _q(dotnet) - for _, arg in ipairs(argv) do - cmd = cmd .. " " .. _q(arg) - end - os.vrun(cmd, runopt) - elseif os.run then - local cmd = _q(dotnet) - for _, arg in ipairs(argv) do - cmd = cmd .. " " .. _q(arg) - end - os.run(cmd, runopt) - else - local targetdir = target:targetdir() - if targetdir and os.isdir(targetdir) then - os.cp(path.join(targetdir, "**"), install_abs, {rootdir = targetdir}) - end - end + os.vrunv(dotnet, argv, {curdir = path.directory(csprojfile), envs = compinst:runenvs()}) + -- copy published files to installdir + local installdir = target:installdir() if target:is_binary() then - local targetdir = target:targetdir() - if targetdir and os.isdir(targetdir) then - os.cp(path.join(targetdir, "**"), install_abs, {rootdir = targetdir}) - end + installdir = target:installdir("bin") + elseif target:is_static() or target:is_shared() then + installdir = target:installdir("lib") + end + if installdir and #installdir > 0 then + local install_abs = path.is_absolute(installdir) and installdir or path.absolute(installdir, os.projectdir()) + os.mkdir(install_abs) + os.cp(path.join(tmpdir, "**"), install_abs, {rootdir = tmpdir}) end + end diff --git a/xmake/rules/csharp/installcmd.lua b/xmake/rules/csharp/installcmd.lua deleted file mode 100644 index 7e1e385b4..000000000 --- a/xmake/rules/csharp/installcmd.lua +++ /dev/null @@ -1,59 +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 installcmd.lua --- - -import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) - -function main(target, batchcmds, opt) - 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() - - local install_path = target:installdir() - if target:is_binary() then - install_path = target:installdir("bin") - elseif target:is_static() or target:is_shared() then - install_path = target:installdir("lib") - end - - local install_abs - local argv = { - "publish", csprojfile, - "--nologo", - "--configuration", configuration, - "--verbosity", verbosity - } - if install_path and #install_path > 0 then - install_abs = path.is_absolute(install_path) and install_path or path.absolute(install_path, os.projectdir()) - table.join2(argv, {"--output", install_abs}) - end - - local rid = csharp_common.get_runtime_identifier(target) - if rid and target:is_binary() then - table.join2(argv, {"--runtime", rid}) - end - csharp_common.append_target_flags(target, argv) - - batchcmds:show_progress(opt.progress, "${color.build.target}publishing.csharp.$(mode) %s", target:name()) - if install_abs then - batchcmds:mkdir(install_abs) - end - batchcmds:vrunv(dotnet, argv, csharp_common.get_dotnet_runopt(csprojfile)) -end diff --git a/xmake/rules/csharp/load.lua b/xmake/rules/csharp/load.lua deleted file mode 100644 index 14b53a1fa..000000000 --- a/xmake/rules/csharp/load.lua +++ /dev/null @@ -1,65 +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 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 - target:set("targetdir", path.join(targetdir, target:name())) - end - - if target:is_static() or target:is_shared() then - if not target:get("extension") then - target:set("extension", ".dll") - end - if target:get("prefixname") == nil then - target:set("prefixname", "") - end - end - - -- find and cache the .csproj file for later use in build/install - local csprojfiles = {} - for _, sourcefile in ipairs(target:sourcefiles()) do - if path.extension(sourcefile):lower() == ".csproj" then - table.insert(csprojfiles, sourcefile) - end - end - assert(#csprojfiles <= 1, "target(%s): csharp only supports one .csproj file!", target:name()) - - 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)) - end - target:data_set("csharp.csproj", csprojabs) -end diff --git a/xmake/rules/csharp/modules/csharp_common.lua b/xmake/rules/csharp/modules/csharp_common.lua index dce35021a..516297a45 100644 --- a/xmake/rules/csharp/modules/csharp_common.lua +++ b/xmake/rules/csharp/modules/csharp_common.lua @@ -169,64 +169,3 @@ function get_runtime_identifier(target) 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/xmake.lua b/xmake/rules/csharp/xmake.lua index b5e76dfa9..9ad5f7974 100644 --- a/xmake/rules/csharp/xmake.lua +++ b/xmake/rules/csharp/xmake.lua @@ -14,104 +14,36 @@ -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- --- @author JassJam +-- @author ruki -- @file xmake.lua -- --- define rule: build csharp target with dotnet --- --- @code --- target("app") --- set_kind("binary") -- or "shared" --- add_rules("csharp") --- add_files("src/*.cs") --- --- -- 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.<prop>", <value>) -- 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 Sdk="..."> (project attribute) (defaults to "Microsoft.NET.Sdk") --- -- csharp.target_frameworks => <TargetFrameworks> (list, ';' separated) --- -- csharp.target_framework => <TargetFramework> (defaults to latest installed dotnet sdk major, e.g. net8.0) --- -- csharp.implicit_usings => <ImplicitUsings> --- -- csharp.nullable => <Nullable> --- -- csharp.lang_version => <LangVersion> --- -- csharp.enable_default_compile_items => <EnableDefaultCompileItems> --- -- csharp.enable_default_embedded_resource_items => <EnableDefaultEmbeddedResourceItems> --- -- csharp.enable_default_none_items => <EnableDefaultNoneItems> --- -- csharp.root_namespace => <RootNamespace> --- -- default/derived: set_basename(...) => <AssemblyName> --- -- csharp.generate_assembly_info => <GenerateAssemblyInfo> --- -- csharp.deterministic => <Deterministic> --- -- default/derived: set_optimize(...) => <Optimize> --- -- default/derived: get_plat()/get_arch() => <PlatformTarget> --- -- csharp.prefer_32bit => <Prefer32Bit> --- -- csharp.allow_unsafe_blocks => <AllowUnsafeBlocks> --- -- csharp.check_for_overflow_underflow => <CheckForOverflowUnderflow> --- -- default/derived: set_warnings(...) => <WarningLevel> --- -- csharp.analysis_level => <AnalysisLevel> --- -- csharp.enable_net_analyzers => <EnableNETAnalyzers> --- -- csharp.enforce_code_style_in_build => <EnforceCodeStyleInBuild> --- -- default/derived: set_warnings("error") => <TreatWarningsAsErrors>true</...> --- -- csharp.warnings_as_errors => <WarningsAsErrors> (list, ';' separated) --- -- csharp.warnings_not_as_errors => <WarningsNotAsErrors> (list, ';' separated) --- -- default/derived: add_defines(...) => <DefineConstants> --- -- csharp.error_log => <ErrorLog> --- -- default/derived: set_symbols(...) => <DebugType>/<DebugSymbols> --- -- csharp.generate_documentation_file => <GenerateDocumentationFile> --- -- csharp.documentation_file => <DocumentationFile> --- -- csharp.runtime_identifier => <RuntimeIdentifier> --- -- csharp.runtime_identifiers => <RuntimeIdentifiers> (list, ';' separated) --- -- csharp.self_contained => <SelfContained> --- -- csharp.use_app_host => <UseAppHost> --- -- csharp.roll_forward => <RollForward> --- -- csharp.publish_single_file => <PublishSingleFile> --- -- csharp.publish_trimmed => <PublishTrimmed> --- -- csharp.trim_mode => <TrimMode> --- -- csharp.publish_ready_to_run => <PublishReadyToRun> --- -- csharp.invariant_globalization => <InvariantGlobalization> --- -- csharp.include_native_libraries_for_self_extract => <IncludeNativeLibrariesForSelfExtract> --- -- csharp.enable_compression_in_single_file => <EnableCompressionInSingleFile> --- -- csharp.publish_aot => <PublishAot> --- -- csharp.strip_symbols => <StripSymbols> --- -- csharp.enable_trim_analyzer => <EnableTrimAnalyzer> --- -- csharp.json_serializer_is_reflection_enabled_by_default => <JsonSerializerIsReflectionEnabledByDefault> --- -- csharp.satellite_resource_languages => <SatelliteResourceLanguages> (list, ';' separated) --- -- csharp.version => <Version> --- -- csharp.assembly_version => <AssemblyVersion> --- -- csharp.file_version => <FileVersion> --- -- csharp.informational_version => <InformationalVersion> --- -- csharp.package_id => <PackageId> --- -- csharp.authors => <Authors> --- -- csharp.company => <Company> --- -- csharp.product => <Product> --- -- csharp.description => <Description> --- -- csharp.copyright => <Copyright> --- -- csharp.repository_url => <RepositoryUrl> --- -- csharp.repository_type => <RepositoryType> --- -- csharp.package_license_expression => <PackageLicenseExpression> --- -- csharp.package_project_url => <PackageProjectUrl> --- -- csharp.neutral_language => <NeutralLanguage> --- -- csharp.enable_preview_features => <EnablePreviewFeatures> --- -- csharp.generate_runtime_configuration_files => <GenerateRuntimeConfigurationFiles> --- -- csharp.copy_local_lock_file_assemblies => <CopyLocalLockFileAssemblies> --- -- csharp.append_target_framework_to_output_path => <AppendTargetFrameworkToOutputPath> (default: false) --- -- csharp.append_runtime_identifier_to_output_path => <AppendRuntimeIdentifierToOutputPath> (default: false) --- -- csharp.produce_reference_assembly => <ProduceReferenceAssembly> --- -- csharp.disable_implicit_framework_references => <DisableImplicitFrameworkReferences> --- -- csharp.generate_target_framework_attribute => <GenerateTargetFrameworkAttribute> --- @endcode --- +rule("csharp.build") + set_sourcekinds("cs") + on_load(function (target) + import("modules.csharp_common", {rootdir = os.scriptdir(), alias = "csharp_common"}) + + -- set target extension and prefix + if target:is_shared() then + if not target:get("extension") then + target:set("extension", ".dll") + end + if target:get("prefixname") == nil then + target:set("prefixname", "") + end + end + + -- find or generate .csproj file + local csprojfile = csharp_common.find_or_generate_csproj(target, {skip_deps = true}) + if csprojfile then + target:data_set("csharp.csproj", csprojfile) + if not target:get("filename") and not target:get("basename") then + target:set("basename", path.basename(csprojfile)) + end + end + end) + on_build("build.target") + rule("csharp") - set_extensions(".cs", ".csproj") - set_sourcekinds("cs", "csproj", {objectfiles = false}) - on_load("load") - on_buildcmd("buildcmd") - on_clean("clean") - on_install("install") - on_installcmd("installcmd") + add_deps("csharp.build") + add_deps("utils.inherit.links") |
