diff options
Diffstat (limited to 'xmake/rules')
| -rw-r--r-- | xmake/rules/csharp/build.lua | 86 | ||||
| -rw-r--r-- | xmake/rules/csharp/config.lua | 47 | ||||
| -rw-r--r-- | xmake/rules/csharp/generator/csproj.lua | 257 | ||||
| -rw-r--r-- | xmake/rules/csharp/generator/itemgroups.lua | 163 | ||||
| -rw-r--r-- | xmake/rules/csharp/generator/properties.lua | 174 | ||||
| -rw-r--r-- | xmake/rules/csharp/install.lua | 80 | ||||
| -rw-r--r-- | xmake/rules/csharp/installcmd.lua | 83 | ||||
| -rw-r--r-- | xmake/rules/csharp/xmake.lua | 131 |
8 files changed, 1021 insertions, 0 deletions
diff --git a/xmake/rules/csharp/build.lua b/xmake/rules/csharp/build.lua new file mode 100644 index 000000000..9bc6f2e76 --- /dev/null +++ b/xmake/rules/csharp/build.lua @@ -0,0 +1,86 @@ +--!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 target.lua +-- + +-- imports +import("core.base.option") +import("core.tool.compiler") +import("core.project.depend") +import("utils.progress") + +-- build the source files +function build_sourcefiles(target, sourcebatch, opt) + + -- get the target file + local targetfile = target:targetfile() + + -- get source files and kind + local sourcefiles = sourcebatch.sourcefiles + local sourcekind = sourcebatch.sourcekind + local csprojfile = target:data("csharp.csproj") + + -- get depend file + local dependfile = target:dependfile(targetfile) + + -- load compiler + local compinst = compiler.load(sourcekind, {target = target}) + + -- get compile flags + local compflags = compinst:compflags({target = target}) + + -- load dependent info + local dependinfo = option.get("rebuild") and {} or (depend.load(dependfile) or {}) + + -- need build this target? + local depvalues = {compinst:program(), compflags} + if not depend.is_changed(dependinfo, {lastmtime = os.mtime(targetfile), values = depvalues}) then + return + end + + -- trace progress info + progress.show(opt.progress, "${color.build.target}linking.$(mode) %s", path.filename(targetfile)) + + -- trace verbose info + vprint(compinst:buildcmd(sourcefiles, targetfile, {target = target, compflags = compflags})) + + -- flush io buffer to update progress info + io.flush() + + -- build it + dependinfo.files = {} + assert(compinst:build(sourcefiles, targetfile, {target = target, dependinfo = dependinfo, compflags = compflags})) + + -- update files and values to the dependent file + dependinfo.values = depvalues + table.join2(dependinfo.files, sourcefiles, csprojfile) + depend.save(dependinfo, dependfile) +end + +-- build target +function main(target, opt) + + -- @note only support one source kind! + local sourcebatches = target:sourcebatches() + if sourcebatches then + local sourcebatch = sourcebatches["csharp.build"] + if sourcebatch then + build_sourcefiles(target, sourcebatch, opt) + end + end +end diff --git a/xmake/rules/csharp/config.lua b/xmake/rules/csharp/config.lua new file mode 100644 index 000000000..3f6b71844 --- /dev/null +++ b/xmake/rules/csharp/config.lua @@ -0,0 +1,47 @@ +--!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 config.lua +-- + +-- imports +import("core.project.depend") +import("generator.csproj", {rootdir = os.scriptdir(), alias = "generate_csproj"}) + +function main(target) + + -- compute csproj path + local csprojfile = path.join(target:autogendir(), "rules", "csharp", target:name() .. ".csproj") + local dependfile = target:dependfile(csprojfile) + + -- collect source files and dep csproj paths as depend values + local sourcefiles = target:sourcefiles() + local depcsproj = {} + for _, dep in ipairs(target:orderdeps()) do + local depcsproj_path = dep:data("csharp.csproj") + if depcsproj_path then + table.insert(depcsproj, depcsproj_path) + end + end + + -- generate csproj incrementally + depend.on_changed(function () + generate_csproj(target, csprojfile) + end, {dependfile = dependfile, files = sourcefiles, values = depcsproj}) + + target:data_set("csharp.csproj", csprojfile) +end diff --git a/xmake/rules/csharp/generator/csproj.lua b/xmake/rules/csharp/generator/csproj.lua new file mode 100644 index 000000000..aa4e0434c --- /dev/null +++ b/xmake/rules/csharp/generator/csproj.lua @@ -0,0 +1,257 @@ +--!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.lua +-- + +-- imports +import("properties") +import("itemgroups") + +-- escape special xml characters +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 + +-- format key-value pairs as xml attributes string, e.g. ` Sdk="Microsoft.NET.Sdk"` +function _format_attributes(attrs) + if type(attrs) ~= "table" then + return "" + end + local keys = {} + for key, value in table.orderpairs(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 + +-- get single csharp value from target:values(), with default fallback +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 + +-- resolve a registry entry value, supports custom resolve function, list type and single value +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 + +-- collect <Project> element attributes, e.g. Sdk="Microsoft.NET.Sdk" +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 + +-- collect <PropertyGroup> entries from registered csharp.* properties +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 + +-- normalize item entry to {xml, attrs, value} format +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 table.orderpairs(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 + +-- collect <ItemGroup> entries (Compile, ProjectReference, PackageReference, ..) +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 + +-- collect custom properties from target:values("csharp.properties") +-- value format: "Name=Value", e.g. set_values("csharp.properties", "MyProp=value") +function _collect_custom_property_entries(target) + local entries = {} + for _, item in ipairs(table.wrap(target:values("csharp.properties"))) do + local name, value = tostring(item):match("^%s*([^=]+)%s*=(.*)$") + if name and #value > 0 then + table.insert(entries, {xml = name:trim(), value = value}) + end + end + return entries +end + +-- render <PropertyGroup> section to file +function _render_property_group(file, entries) + if #entries == 0 then + return + end + file:print(" <PropertyGroup>") + for _, entry in ipairs(entries) do + file:print(" <%s>%s</%s>", entry.xml, _xml_escape(entry.value), entry.xml) + end + file:print(" </PropertyGroup>") +end + +-- render <ItemGroup> sections to file +function _render_item_groups(file, item_groups) + for _, group in ipairs(item_groups) do + if #group.items > 0 then + file:print(" <ItemGroup>") + for _, item in ipairs(group.items) do + local attrs = _format_attributes(item.attrs) + if item.value ~= nil and item.value ~= "" then + file:print(" <%s%s>%s</%s>", item.xml, attrs, _xml_escape(item.value), item.xml) + else + file:print(" <%s%s />", item.xml, attrs) + end + end + file:print(" </ItemGroup>") + end + end +end + +-- generate .csproj file for the target, write to tmpfile first then copy if different +function main(target, csprojfile, opt) + opt = opt or {} + + local csprojdir = path.directory(csprojfile) + local context = { + target = target, + csprojfile = csprojfile, + csprojdir = csprojdir, + opt = opt + } + + -- collect project properties + local property_registry_entries = properties() + local item_registry_entries = 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) + + -- generate csproj + local tmpfile = os.tmpfile() .. ".csproj" + local file = io.open(tmpfile, "w") + file:print("<Project%s>", _format_attributes(project_attributes)) + _render_property_group(file, property_entries) + _render_item_groups(file, item_groups) + file:print("</Project>") + file:close() + + os.mkdir(csprojdir) + os.cp(tmpfile, csprojfile, {copy_if_different = true}) + os.rm(tmpfile) +end diff --git a/xmake/rules/csharp/generator/itemgroups.lua b/xmake/rules/csharp/generator/itemgroups.lua new file mode 100644 index 000000000..2c0528665 --- /dev/null +++ b/xmake/rules/csharp/generator/itemgroups.lua @@ -0,0 +1,163 @@ +--!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 itemgroups.lua +-- + +-- normalize path to relative and use forward slashes +function _normalize_relative(fromdir, targetpath) + local relpath = path.relative(targetpath, fromdir) or targetpath + return path.unix(relpath) +end + +-- collect .cs source files as relative paths to csprojdir +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 + +-- collect ProjectReference paths from dependency targets +function _collect_project_references(context) + local references = {} + for _, dep in ipairs(context.target:orderdeps()) do + local depcsproj = dep:data("csharp.csproj") + if depcsproj then + table.insert(references, _normalize_relative(context.csprojdir, depcsproj)) + end + end + table.sort(references) + return table.unique(references) +end + +-- extract nuget package name and version from package require string +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 + +-- collect PackageReference entries from nuget packages +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 table.orderpairs(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 + +-- register all item group entries (Compile, ProjectReference, PackageReference) +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/generator/properties.lua b/xmake/rules/csharp/generator/properties.lua new file mode 100644 index 000000000..15702eae4 --- /dev/null +++ b/xmake/rules/csharp/generator/properties.lua @@ -0,0 +1,174 @@ +--!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 +-- + +-- check if target has multi-target frameworks set +function _has_target_frameworks(context) + return #table.wrap(context.target:values("csharp.target_frameworks")) > 0 +end + +-- get the first element if value is a table +function _first(value) + if type(value) == "table" then + return value[1] + end + return value +end + +-- get single value from target:values() +function _get_target_value(target, name) + return _first(target:values(name)) +end + +-- get default target framework from dotnet toolchain sdk version, e.g. "net8.0" +function _get_default_target_framework(context) + local major + local toolchain = context.target:toolchain("dotnet") + if toolchain then + local sdkver = toolchain:config("sdkver") + if sdkver then + major = tonumber(tostring(sdkver):match("^(%d+)")) + end + end + return "net" .. tostring(major or 8) .. ".0" +end + +-- resolve target framework from user config or auto-detect from dotnet sdk +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 + +-- resolve assembly name from target basename +function _resolve_assembly_name(context) + local basename = context.target:basename() + if basename ~= nil and #tostring(basename) > 0 then + return basename + end +end + + +-- register a single-value csharp.* property entry +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 + +-- register a list-value csharp.* property entry (semicolon-joined) +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 + +-- register all csharp property and project attribute entries for csproj generation +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_property(register, "prefer_32bit", "Prefer32Bit") + _register_property(register, "allow_unsafe_blocks", "AllowUnsafeBlocks") + _register_property(register, "check_for_overflow_underflow", "CheckForOverflowUnderflow") + _register_property(register, "analysis_level", "AnalysisLevel") + _register_property(register, "enable_net_analyzers", "EnableNETAnalyzers") + _register_property(register, "enforce_code_style_in_build", "EnforceCodeStyleInBuild") + _register_list_property(register, "warnings_as_errors", "WarningsAsErrors") + _register_list_property(register, "warnings_not_as_errors", "WarningsNotAsErrors") + _register_property(register, "error_log", "ErrorLog") + _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/install.lua b/xmake/rules/csharp/install.lua new file mode 100644 index 000000000..03e2cd24d --- /dev/null +++ b/xmake/rules/csharp/install.lua @@ -0,0 +1,80 @@ +--!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 install.lua +-- + +-- imports +import("core.project.config") + +-- get dotnet program +function _get_dotnet(target) + return target:tool("cs") or "dotnet" +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 + +-- get output directory based on target kind +-- on windows, shared libraries (dll) should also go to bindir +function _get_outputdir(target) + if target:is_binary() or (target:is_shared() and target:is_plat("windows", "mingw")) then + return target:bindir() + else + return target:libdir() + end +end + +-- install csharp target using dotnet publish +function main(target) + local installdir = target:installdir() + if not installdir then + return + end + + -- get output directory based on target kind + local outputdir = _get_outputdir(target) + if not outputdir then + return + end + + -- run dotnet publish + local csprojfile = target:data("csharp.csproj") + local argv = {"publish"} + if csprojfile then + table.insert(argv, csprojfile) + end + table.join2(argv, {"--nologo", + "--configuration", _get_configuration(), + "--output", outputdir}) + local dotnet = _get_dotnet(target) + os.vrunv(dotnet, argv) + + -- install extra files (add_installfiles) + local srcfiles, dstfiles = target:installfiles(installdir) + if srcfiles and dstfiles then + for idx, srcfile in ipairs(srcfiles) do + os.vcp(srcfile, dstfiles[idx]) + end + end +end diff --git a/xmake/rules/csharp/installcmd.lua b/xmake/rules/csharp/installcmd.lua new file mode 100644 index 000000000..25de92989 --- /dev/null +++ b/xmake/rules/csharp/installcmd.lua @@ -0,0 +1,83 @@ +--!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 installcmd.lua +-- + +-- imports +import("core.project.config") + +-- get dotnet program +function _get_dotnet(target) + return target:tool("cs") or "dotnet" +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 + +-- install csharp target for xpack using dotnet publish +function main(target, batchcmds, opt) + local package = opt.package + if not package then + return + end + + local installdir = package:installdir() + if not installdir then + return + end + + -- get output directory based on target kind + -- on windows, shared libraries (dll) should also go to bindir + local outputdir + if target:is_binary() or (target:is_shared() and target:is_plat("windows", "mingw")) then + outputdir = package:installdir("bin") + else + outputdir = package:installdir("lib") + end + + -- run dotnet publish to a temporary publish directory, then copy to install directory + local publishdir = path.join(target:autogendir(), "rules", "csharp", "publish") + local csprojfile = target:data("csharp.csproj") + local argv = {"publish"} + if csprojfile then + table.insert(argv, csprojfile) + end + table.join2(argv, {"--nologo", + "--configuration", _get_configuration(), + "--output", publishdir}) + local dotnet = _get_dotnet(target) + batchcmds:vrunv(dotnet, argv) + + -- copy published files to output directory + batchcmds:mkdir(outputdir) + batchcmds:cp(path.join(publishdir, "**"), outputdir, {rootdir = publishdir}) + + -- install extra files (add_installfiles) + local srcfiles, dstfiles = target:installfiles(installdir) + if srcfiles and dstfiles then + for idx, srcfile in ipairs(srcfiles) do + batchcmds:cp(srcfile, dstfiles[idx]) + end + end +end diff --git a/xmake/rules/csharp/xmake.lua b/xmake/rules/csharp/xmake.lua new file mode 100644 index 000000000..9a0a6e43b --- /dev/null +++ b/xmake/rules/csharp/xmake.lua @@ -0,0 +1,131 @@ +--!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 +-- + +-- User Configs: +-- +-- The following `csharp.*` values can be set via `set_values()` in xmake.lua +-- to customize the auto-generated .csproj file. +-- +-- e.g. +-- target("example") +-- add_rules("csharp") +-- add_files("src/*.cs") +-- set_values("csharp.target_framework", "net8.0") +-- set_values("csharp.nullable", "disable") +-- set_values("csharp.allow_unsafe_blocks", "true") +-- +-- Project: +-- csharp.sdk - Project Sdk (default: Microsoft.NET.Sdk) +-- +-- General: +-- csharp.target_framework - e.g. "net8.0", auto-detected from dotnet sdk if not set +-- csharp.target_frameworks - multi-target, e.g. {"net8.0", "net9.0"} (list, semicolon-joined) +-- csharp.implicit_usings - ImplicitUsings (default: "enable") +-- csharp.nullable - Nullable (default: "enable") +-- csharp.lang_version - LangVersion, e.g. "12.0", "latest" +-- csharp.root_namespace - RootNamespace +-- csharp.enable_default_compile_items - EnableDefaultCompileItems (default: "false") +-- csharp.enable_default_embedded_resource_items - EnableDefaultEmbeddedResourceItems +-- csharp.enable_default_none_items - EnableDefaultNoneItems +-- +-- Build: +-- csharp.generate_assembly_info - GenerateAssemblyInfo +-- csharp.deterministic - Deterministic +-- csharp.prefer_32bit - Prefer32Bit +-- csharp.allow_unsafe_blocks - AllowUnsafeBlocks +-- csharp.check_for_overflow_underflow - CheckForOverflowUnderflow +-- +-- Analysis: +-- csharp.analysis_level - AnalysisLevel +-- csharp.enable_net_analyzers - EnableNETAnalyzers +-- csharp.enforce_code_style_in_build - EnforceCodeStyleInBuild +-- csharp.warnings_as_errors - WarningsAsErrors (list) +-- csharp.warnings_not_as_errors - WarningsNotAsErrors (list) +-- csharp.error_log - ErrorLog +-- csharp.generate_documentation_file - GenerateDocumentationFile +-- csharp.documentation_file - DocumentationFile +-- +-- Publish/Runtime: +-- csharp.runtime_identifier - RuntimeIdentifier, e.g. "win-x64" +-- csharp.runtime_identifiers - RuntimeIdentifiers (list) +-- 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) +-- +-- Package Info: +-- 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 +-- +-- Output: +-- 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 +-- +-- Custom Properties (for arbitrary csproj properties not listed above): +-- csharp.properties - add custom <PropertyGroup> entries, format: "Name=Value" +-- e.g. set_values("csharp.properties", "MyProp=value", "AnotherProp=value2") +-- +rule("csharp.build") + set_sourcekinds("cs") + on_load(function (target) + -- dotnet always outputs .dll for libraries, and no prefix + if target:is_shared() or target:is_static() then + target:set("prefixname", "") + target:set("extension", ".dll") + end + end) + on_config("config") + on_build("build") + on_install("install") + on_installcmd("installcmd") + +rule("csharp") + add_deps("csharp.build") + add_deps("utils.inherit.links") |
