Skip to content

Commit

Permalink
Initially add C# support for VS proj generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Kethers committed Dec 29, 2023
1 parent eddd355 commit 6e17c82
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 15 deletions.
14 changes: 12 additions & 2 deletions xmake/plugins/project/vstudio/impl/vs200x.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import("core.project.project")
import("vs200x_solution")
import("vs200x_vcproj")
import("vs_csproj")

-- make vstudio project
function make(outputdir, vsinfo)
Expand All @@ -44,8 +45,17 @@ function make(outputdir, vsinfo)

-- make vsprojs
for _, target in pairs(project.targets()) do
if not target:is_phony() then
vs200x_vcproj.make(vsinfo, target)
for _, sourcebatch in pairs(target:sourcebatches()) do
local sourcekind = sourcebatch.sourcekind
if sourcekind == "cc" or sourcekind == "cxx" then
if not target:is_phony() then
vs200x_vcproj.make(vsinfo, target)
end
break
elseif sourcekind == "cs" then
vs_csproj.make(vsinfo, target)
break
end
end
end

Expand Down
22 changes: 18 additions & 4 deletions xmake/plugins/project/vstudio/impl/vs200x_solution.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,29 @@ end
-- make projects
function _make_projects(slnfile, vsinfo)

-- the vstudio tool uuid for vc project
local vctool = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"

-- make all targets
for targetname, target in pairs(project.targets()) do

tool_id = "" -- the vstudio tool uuid for project
proj_extension = ""

for _, sourcebatch in pairs(target:sourcebatches()) do
local sourcekind = sourcebatch.sourcekind
if sourcekind == "cc" or sourcekind == "cxx" then
tool_id = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
proj_extension = "vcxproj"
break
elseif sourcekind == "cs" then
tool_id = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
proj_extension = "csproj"
break
end
end

if not target:is_phony() then

-- enter project
slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid4(targetname))
slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.%s\", \"{%s}\"", tool_id, targetname, targetname, targetname, proj_extension, hash.uuid4(targetname))

-- add dependences
for _, dep in ipairs(target:get("deps")) do
Expand Down
17 changes: 13 additions & 4 deletions xmake/plugins/project/vstudio/impl/vs201x.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import("core.tool.toolchain")
import("vs201x_solution")
import("vs201x_vcxproj")
import("vs201x_vcxproj_filters")
import("vs_csproj")
import("vsutils")
import("core.cache.memcache")
import("core.cache.localcache")
Expand Down Expand Up @@ -288,7 +289,7 @@ function _make_targetinfo(mode, arch, target, vcxprojdir)
for _, sourcebatch in table.orderpairs(sourcebatches) do
local sourcekind = sourcebatch.sourcekind
local rulename = sourcebatch.rulename
if sourcekind then
if sourcekind and sourcekind ~= "cs" then -- TODO: temp, delete it when cs flags are done
for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do
local compflags = compiler.compflags(sourcefile, {target = target, sourcekind = sourcekind})
if not firstcompflags and (rulename == "c.build" or rulename == "c++.build" or rulename == "cuda.build") then
Expand Down Expand Up @@ -567,10 +568,18 @@ function make(outputdir, vsinfo)
-- make solution
vs201x_solution.make(vsinfo)

-- make .vcxproj
-- make .vcxproj and .csproj
for _, target in table.orderpairs(targets) do
vs201x_vcxproj.make(vsinfo, target)
vs201x_vcxproj_filters.make(vsinfo, target)
for _, targetinfo in ipairs(target.info) do
if targetinfo.sourcekinds and table.contains(targetinfo.sourcekinds, "cc", "cxx") then
vs201x_vcxproj.make(vsinfo, target)
vs201x_vcxproj_filters.make(vsinfo, target)
break
elseif targetinfo.sourcekinds and table.contains(targetinfo.sourcekinds, "cs") then
vs_csproj.make(vsinfo, target)
break
end
end
end

-- clear local cache
Expand Down
18 changes: 16 additions & 2 deletions xmake/plugins/project/vstudio/impl/vs201x_solution.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ function _make_projects(slnfile, vsinfo)
-- make all targets
local groups = {}
local targets = {}
local vctool = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
for targetname, target in table.orderpairs(project.targets()) do
-- we need to set startup project for default or binary target
-- @see https://github.com/xmake-io/xmake/issues/1249
Expand All @@ -53,8 +52,23 @@ function _make_projects(slnfile, vsinfo)
end
end
for _, target in ipairs(targets) do
tool_id = ""
proj_extension = ""
for _, sourcebatch in pairs(target:sourcebatches()) do
local sourcekind = sourcebatch.sourcekind
if sourcekind == "cc" or sourcekind == "cxx" then
tool_id = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
proj_extension = "vcxproj"
break
elseif sourcekind == "cs" then
tool_id = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
proj_extension = "csproj"
break
end
end

local targetname = target:name()
slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid4(targetname))
slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.%s\", \"{%s}\"", tool_id, targetname, targetname, targetname, proj_extension, hash.uuid4(targetname))
for _, dep in ipairs(target:get("deps")) do
slnfile:enter("ProjectSection(ProjectDependencies) = postProject")
slnfile:print("{%s} = {%s}", hash.uuid4(dep), hash.uuid4(dep))
Expand Down
214 changes: 214 additions & 0 deletions xmake/plugins/project/vstudio/impl/vs_csproj.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
--!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, TBOOX Open Source Group.
--
-- @author Kethers
-- @file vs_csproj.lua
--

-- imports
import("core.base.option")
import("core.base.hashset")
import("core.project.rule")
import("core.project.config")
import("core.project.project")
import("core.language.language")
import("core.tool.toolchain")
import("private.utils.batchcmds")
import("vsfile")
import("vsutils")
import("plugins.project.vsxmake.getinfo", {rootdir = os.programdir()})


function _make_dirs(dir, csprojdir)
dir = dir:trim()
if #dir == 0 then
return ""
end
dir = path.translate(dir)
if not path.is_absolute(dir) then
dir = path.relative(path.absolute(dir), csprojdir)
end
return dir
end

-- make header
function _make_header(csprojfile, vsinfo)
csprojfile:print("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
csprojfile:enter("<Project DefaultTargets=\"Build\" ToolsVersion=\"%s.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">", assert(vsinfo.project_version))
end

function _make_configurations(csprojfile, vsinfo, target)
-- the target name
local targetname = target.name

-- init configuration type
local output_types =
{
binary = "Exe"
-- , winexe = "WinExe" TODO: this kind doesn't exist yet
, shared = "Library"
}

-- import Microsoft.Common.props
csprojfile:print("<Import Project=\"%$(MSBuildExtensionsPath)\\%$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists(\'%$(MSBuildExtensionsPath)\\%$(MSBuildToolsVersion)\\Microsoft.Common.props\')\" />")

-- make Globals
csprojfile:enter("<PropertyGroup>")
csprojfile:print("<Configuration Condition=\" \'%$(Configuration)\' == \'\' \">debug</Configuration>")
csprojfile:print("<Platform Condition=\" \'%$(Platform)\' == \'\' \">x64</Platform>")
csprojfile:print("<ProjectGuid>{%s}</ProjectGuid>", hash.uuid4(targetname))
csprojfile:print("<OutputType>%s</OutputType>", output_types[target.kind] or "Unknown")
csprojfile:print("<AppDesignerFolder>Properties</AppDesignerFolder>")
csprojfile:print("<RootNamespace>%s</RootNamespace>", targetname)
csprojfile:print("<AssemblyName>%s</AssemblyName>", targetname)
csprojfile:print("<TargetFrameworkVersion>v%s</TargetFrameworkVersion>", vsinfo.dotnetframework_version)
csprojfile:print("<FileAlignment>512</FileAlignment>")
csprojfile:print("<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>")
csprojfile:leave("</PropertyGroup>")

-- make Configuration
for _, targetinfo in ipairs(target.info) do
local mode = targetinfo.mode
local arch = targetinfo.arch

symbols = vsinfo._targets[targetname]._targets[mode][arch].symbols or ""
optimize = vsinfo._targets[targetname]._targets[mode][arch].optimize or ""

debugtype = "portable"
debugsymbols = "true"
if (symbols == "debug") then
debugtype = "full"
debugsymbols = "true"
elseif (symbols == "hidden") then
debugtype = "none"
debugsymbols = "false"
elseif (string.find(symbols, "debug") and string.find(symbols, "embed")) then
debugtype = "embedded"
debugsymbols = "true"
end

if optimize == "" or optimize == "none" then
optimize = "false"
else
optimize = "true"
end

csprojfile:enter("<PropertyGroup Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\" >", mode, arch)
csprojfile:print("<DebugType>%s</DebugType>", debugtype)
csprojfile:print("<DebugSymbols>%s</DebugSymbols>", debugsymbols)
csprojfile:print("<Optimize>%s</Optimize>", optimize)
csprojfile:print("<OutputPath>%s</OutputPath>", _make_dirs(targetinfo.targetdir, target.project_dir))
csprojfile:print("<BaseIntermediateOutputPath>%s</BaseIntermediateOutputPath>", _make_dirs(targetinfo.objectdir, target.project_dir))
csprojfile:print("<IntermediateOutputPath>%$(BaseIntermediateOutputPath)</IntermediateOutputPath>")
csprojfile:print("<DefineConstants>%s</DefineConstants>", vsinfo._targets[targetname]._targets[mode][arch].defines)
csprojfile:print("<ErrorReport>prompt</ErrorReport>")
csprojfile:print("<WarningLevel>4</WarningLevel>")
csprojfile:leave("</PropertyGroup>")
end
end

-- make source files
function _make_source_files(csprojfile, vsinfo, target)
-- make source file infos
local sourceinfos = {}
for _, targetinfo in ipairs(target.info) do
for _, sourcebatch in pairs(targetinfo.sourcebatches) do
local sourcekind = sourcebatch.sourcekind
local rulename = sourcebatch.rulename
if (sourcekind == "cs") then
local objectfiles = sourcebatch.objectfiles
for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do
local objectfile = objectfiles[idx]
-- local flags = targetinfo.sourceflags[sourcefile] -- TODO: cs flags doesn't exist yet
sourceinfos[sourcefile] = sourceinfos[sourcefile] or {}
table.insert(sourceinfos[sourcefile], {targetinfo = targetinfo, mode = targetinfo.mode, arch = targetinfo.arch, sourcekind = sourcekind, objectfile = objectfile, flags = flags, compargv = targetinfo.compargvs[sourcefile]})
end
end
end
end

-- make source files
csprojfile:enter("<ItemGroup>")
for sourcefile, sourceinfo in table.orderpairs(sourceinfos) do
if #sourceinfo == #target.info then
csprojfile:print("<Compile Include=\"%s\" />", path.relative(path.absolute(sourcefile), target.project_dir))
end
end
csprojfile:leave("</ItemGroup>")
end

-- make project references
function _make_project_references(csprojfile, vsinfo, target)
local deps = vsinfo._targets[target.name]._deps

csprojfile:enter("<ItemGroup>")

for depname, dep in table.orderpairs(deps) do
proj_extension = dep.proj_extension
csprojfile:enter("<ProjectReference Include=\"..\\%s\\%s.%s\"> ", depname, depname, proj_extension)
csprojfile:print("<Project>{%s}</Project>", dep.target_id)
csprojfile:print("<Name>%s</Name>", depname)
csprojfile:leave("</ProjectReference>")
end

csprojfile:leave("</ItemGroup>")
end

-- make tailer
function _make_tailer(csprojfile, vsinfo, target)
-- import Microsoft.CSharp.targets
csprojfile:print("<Import Project=\"%$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />")

csprojfile:leave("</Project>")
end

-- make csproj
function make(vsinfo, target)

-- TODO: getinfo will leads to repeat MSVC checking output, try not to use it
local info = getinfo(option.get("outputdir"), vsinfo)

-- the target name
local targetname = target.name

-- the csproj directory
local csprojdir = target.project_dir

-- open csproj file
local csprojpath = path.join(csprojdir, targetname .. ".csproj")
local csprojfile = vsfile.open(csprojpath, "w")

-- init indent character
vsfile.indentchar(' ')

-- make headers
_make_header(csprojfile, info)

-- make Configurations
_make_configurations(csprojfile, info, target)

-- make source files
_make_source_files(csprojfile, info, target)

-- make project references
_make_project_references(csprojfile, info, target)

-- make tailer
_make_tailer(csprojfile, info, target)

-- exit solution file
csprojfile:close()
end
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
See https://github.com/xmake-io/xmake/pull/472 for more infomation.
-->
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="#vs_version#" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="XmakeProgram">
<XmakeProgramDir Condition="'$(XmakeProgramDir)' == ''">$(XMAKE_PROGRAM_DIR)</XmakeProgramDir>
<XmakeProgramDir Condition="'$(XmakeProgramDir)' == ''">#programdir#</XmakeProgramDir>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<ProjectReference Include="..\#target#\#target#.#proj_extension#">
<Project>{#target_id#}</Project>
<Name>{#target#}</Name>
<Name>#target#</Name>
</ProjectReference>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<ProjectReference Include="..\#target#\#target#.#proj_extension#">
<Project>{#target_id#}</Project>
<Name>{#target#}</Name>
<Name>#target#</Name>
</ProjectReference>

0 comments on commit 6e17c82

Please sign in to comment.