You've already forked godot
							
							
				mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-03 11:50:27 +00:00 
			
		
		
		
	Fix .sln project generation logic for Rider to support all OS and all C++ toolchains
Co-authored-by: Andreia Gaita <shana@spoiledcat.net> Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
This commit is contained in:
		@@ -15,3 +15,7 @@ indent_style = space
 | 
			
		||||
[{*.{yml,yaml},.clang{-format,-tidy,d}}]
 | 
			
		||||
indent_size = 2
 | 
			
		||||
indent_style = space
 | 
			
		||||
 | 
			
		||||
[{*.props,*.vcxproj}]
 | 
			
		||||
indent_size = 2
 | 
			
		||||
indent_style = space
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								methods.py
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								methods.py
									
									
									
									
									
								
							@@ -14,6 +14,7 @@ from pathlib import Path
 | 
			
		||||
from typing import Generator, List, Optional, Union, cast
 | 
			
		||||
 | 
			
		||||
from misc.utility.color import print_error, print_info, print_warning
 | 
			
		||||
from platform_methods import detect_arch
 | 
			
		||||
 | 
			
		||||
# Get the "Godot" folder name ahead of time
 | 
			
		||||
base_folder = Path(__file__).resolve().parent
 | 
			
		||||
@@ -1067,8 +1068,22 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
    platform = env["platform"]
 | 
			
		||||
    target = env["target"]
 | 
			
		||||
    arch = env["arch"]
 | 
			
		||||
    host_arch = detect_arch()
 | 
			
		||||
 | 
			
		||||
    host_platform = "windows"
 | 
			
		||||
    if (
 | 
			
		||||
        sys.platform.startswith("linux")
 | 
			
		||||
        or sys.platform.startswith("dragonfly")
 | 
			
		||||
        or sys.platform.startswith("freebsd")
 | 
			
		||||
        or sys.platform.startswith("netbsd")
 | 
			
		||||
        or sys.platform.startswith("openbsd")
 | 
			
		||||
    ):
 | 
			
		||||
        host_platform = "linuxbsd"
 | 
			
		||||
    elif sys.platform == "darwin":
 | 
			
		||||
        host_platform = "macos"
 | 
			
		||||
 | 
			
		||||
    vs_configuration = {}
 | 
			
		||||
    host_vs_configuration = {}
 | 
			
		||||
    common_build_prefix = []
 | 
			
		||||
    confs = []
 | 
			
		||||
    for x in sorted(glob.glob("platform/*")):
 | 
			
		||||
@@ -1097,6 +1112,12 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
            if platform == platform_name:
 | 
			
		||||
                common_build_prefix = msvs.get_build_prefix(env)
 | 
			
		||||
                vs_configuration = vsconf
 | 
			
		||||
            if platform_name == host_platform:
 | 
			
		||||
                host_vs_configuration = vsconf
 | 
			
		||||
                for a in vsconf["arches"]:
 | 
			
		||||
                    if host_arch == a["architecture"]:
 | 
			
		||||
                        host_arch = a["platform"]
 | 
			
		||||
                        break
 | 
			
		||||
        except Exception:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
@@ -1254,12 +1275,11 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
            properties.append(
 | 
			
		||||
                "<ActiveProjectItemList_%s>;%s;</ActiveProjectItemList_%s>" % (x, ";".join(itemlist[x]), x)
 | 
			
		||||
            )
 | 
			
		||||
        output = f"bin\\godot{env['PROGSUFFIX']}"
 | 
			
		||||
        output = os.path.join("bin", f"godot{env['PROGSUFFIX']}")
 | 
			
		||||
 | 
			
		||||
        with open("misc/msvs/props.template", "r", encoding="utf-8") as file:
 | 
			
		||||
            props_template = file.read()
 | 
			
		||||
 | 
			
		||||
        props_template = props_template.replace("%%VSCONF%%", vsconf)
 | 
			
		||||
        props_template = props_template.replace("%%CONDITION%%", condition)
 | 
			
		||||
        props_template = props_template.replace("%%PROPERTIES%%", "\n    ".join(properties))
 | 
			
		||||
        props_template = props_template.replace("%%EXTRA_ITEMS%%", "\n    ".join(extraItems))
 | 
			
		||||
@@ -1272,6 +1292,7 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
 | 
			
		||||
        proplist = [str(j) for j in env["CPPPATH"]]
 | 
			
		||||
        proplist += [str(j) for j in env.get("VSHINT_INCLUDES", [])]
 | 
			
		||||
        proplist += [str(j) for j in get_default_include_paths(env)]
 | 
			
		||||
        props_template = props_template.replace("%%INCLUDES%%", ";".join(proplist))
 | 
			
		||||
 | 
			
		||||
        proplist = env["CCFLAGS"]
 | 
			
		||||
@@ -1307,17 +1328,17 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
 | 
			
		||||
        commands = "scons"
 | 
			
		||||
        if len(common_build_prefix) == 0:
 | 
			
		||||
            commands = "echo Starting SCons && cmd /V /C " + commands
 | 
			
		||||
            commands = "echo Starting SCons & " + commands
 | 
			
		||||
        else:
 | 
			
		||||
            common_build_prefix[0] = "echo Starting SCons && cmd /V /C " + common_build_prefix[0]
 | 
			
		||||
            common_build_prefix[0] = "echo Starting SCons & " + common_build_prefix[0]
 | 
			
		||||
 | 
			
		||||
        cmd = " ^& ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
 | 
			
		||||
        cmd = " ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
 | 
			
		||||
        props_template = props_template.replace("%%BUILD%%", cmd)
 | 
			
		||||
 | 
			
		||||
        cmd = " ^& ".join(common_build_prefix + [" ".join([commands] + cmd_rebuild)])
 | 
			
		||||
        cmd = " ".join(common_build_prefix + [" ".join([commands] + cmd_rebuild)])
 | 
			
		||||
        props_template = props_template.replace("%%REBUILD%%", cmd)
 | 
			
		||||
 | 
			
		||||
        cmd = " ^& ".join(common_build_prefix + [" ".join([commands] + cmd_clean)])
 | 
			
		||||
        cmd = " ".join(common_build_prefix + [" ".join([commands] + cmd_clean)])
 | 
			
		||||
        props_template = props_template.replace("%%CLEAN%%", cmd)
 | 
			
		||||
 | 
			
		||||
        with open(
 | 
			
		||||
@@ -1348,18 +1369,45 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
    section2 = []
 | 
			
		||||
    for conf in confs:
 | 
			
		||||
        godot_platform = conf["platform"]
 | 
			
		||||
        has_editor = "editor" in conf["targets"]
 | 
			
		||||
 | 
			
		||||
        # Skip any platforms that can build the editor and don't match the host platform.
 | 
			
		||||
        #
 | 
			
		||||
        # When both Windows and Mac define an editor target, it's defined as platform+target+arch (windows+editor+x64 for example).
 | 
			
		||||
        # VS only supports two attributes, a "Configuration" and a "Platform", and we currently map our target to the Configuration
 | 
			
		||||
        # (i.e. editor/template_debug/template_release), and our architecture to the "Platform" (i.e. x64, arm64, etc).
 | 
			
		||||
        # Those two are not enough to disambiguate multiple godot targets for different godot platforms with the same architecture,
 | 
			
		||||
        # i.e. editor|x64 would currently match both windows editor intel 64 and linux editor intel 64.
 | 
			
		||||
        #
 | 
			
		||||
        # TODO: More work is needed in order to support generating VS projects that unambiguously support all platform+target+arch variations.
 | 
			
		||||
        # The VS "Platform" has to be a known architecture that VS recognizes, so we can only play around with the "Configuration" part of the combo.
 | 
			
		||||
        if has_editor and godot_platform != host_vs_configuration["platform"]:
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        for p in conf["arches"]:
 | 
			
		||||
            sln_plat = p["platform"]
 | 
			
		||||
            proj_plat = sln_plat
 | 
			
		||||
            godot_arch = p["architecture"]
 | 
			
		||||
 | 
			
		||||
            # Redirect editor configurations for non-Windows platforms to the Windows one, so the solution has all the permutations
 | 
			
		||||
            # and VS doesn't complain about missing project configurations.
 | 
			
		||||
            # Redirect editor configurations for platforms that don't support the editor target to the default editor target on the
 | 
			
		||||
            # active host platform, so the solution has all the permutations and VS doesn't complain about missing project configurations.
 | 
			
		||||
            # These configurations are disabled, so they show up but won't build.
 | 
			
		||||
            if godot_platform != "windows":
 | 
			
		||||
            if not has_editor:
 | 
			
		||||
                section1 += [f"editor|{sln_plat} = editor|{proj_plat}"]
 | 
			
		||||
                section2 += [
 | 
			
		||||
                    f"{{{proj_uuid}}}.editor|{proj_plat}.ActiveCfg = editor|{proj_plat}",
 | 
			
		||||
                section2 += [f"{{{proj_uuid}}}.editor|{proj_plat}.ActiveCfg = editor|{host_arch}"]
 | 
			
		||||
 | 
			
		||||
                configurations += [
 | 
			
		||||
                    f'<ProjectConfiguration Include="editor|{proj_plat}">',
 | 
			
		||||
                    "  <Configuration>editor</Configuration>",
 | 
			
		||||
                    f"  <Platform>{proj_plat}</Platform>",
 | 
			
		||||
                    "</ProjectConfiguration>",
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
                properties += [
 | 
			
		||||
                    f"<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='editor|{proj_plat}'\">",
 | 
			
		||||
                    "  <GodotConfiguration>editor</GodotConfiguration>",
 | 
			
		||||
                    f"  <GodotPlatform>{proj_plat}</GodotPlatform>",
 | 
			
		||||
                    "</PropertyGroup>",
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
            for t in conf["targets"]:
 | 
			
		||||
@@ -1383,21 +1431,6 @@ def generate_vs_project(env, original_args, project_name="godot"):
 | 
			
		||||
                    "</PropertyGroup>",
 | 
			
		||||
                ]
 | 
			
		||||
 | 
			
		||||
                if godot_platform != "windows":
 | 
			
		||||
                    configurations += [
 | 
			
		||||
                        f'<ProjectConfiguration Include="editor|{proj_plat}">',
 | 
			
		||||
                        "  <Configuration>editor</Configuration>",
 | 
			
		||||
                        f"  <Platform>{proj_plat}</Platform>",
 | 
			
		||||
                        "</ProjectConfiguration>",
 | 
			
		||||
                    ]
 | 
			
		||||
 | 
			
		||||
                    properties += [
 | 
			
		||||
                        f"<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='editor|{proj_plat}'\">",
 | 
			
		||||
                        "  <GodotConfiguration>editor</GodotConfiguration>",
 | 
			
		||||
                        f"  <GodotPlatform>{proj_plat}</GodotPlatform>",
 | 
			
		||||
                        "</PropertyGroup>",
 | 
			
		||||
                    ]
 | 
			
		||||
 | 
			
		||||
                p = f"{project_name}.{godot_platform}.{godot_target}.{godot_arch}.generated.props"
 | 
			
		||||
                imports += [
 | 
			
		||||
                    f'<Import Project="$(MSBuildProjectDirectory)\\{p}" Condition="Exists(\'$(MSBuildProjectDirectory)\\{p}\')"/>'
 | 
			
		||||
@@ -1606,3 +1639,18 @@ def to_raw_cstring(value: Union[str, List[str]]) -> str:
 | 
			
		||||
    else:
 | 
			
		||||
        # Wrap multiple segments in parenthesis to suppress `string-concatenation` warnings on clang.
 | 
			
		||||
        return "({})".format(" ".join(f'R"<!>({segment.decode()})<!>"' for segment in split))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_default_include_paths(env):
 | 
			
		||||
    if env.msvc:
 | 
			
		||||
        return []
 | 
			
		||||
    compiler = env.subst("$CXX")
 | 
			
		||||
    target = os.path.join(env.Dir("#main").abspath, "main.cpp")
 | 
			
		||||
    args = [compiler, target, "-x", "c++", "-v"]
 | 
			
		||||
    ret = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
 | 
			
		||||
    output = ret.stdout
 | 
			
		||||
    match = re.search(r"#include <\.\.\.> search starts here:([\S\s]*)End of search list.", output)
 | 
			
		||||
    if not match:
 | 
			
		||||
        print_warning("Failed to find the include paths in the compiler output.")
 | 
			
		||||
        return []
 | 
			
		||||
    return [x.strip() for x in match[1].strip().splitlines()]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								misc/msvs/nmake.substitution.props
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								misc/msvs/nmake.substitution.props
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
      <!-- override the PlatformToolset, which is set in the godot.vcxproj-->
 | 
			
		||||
      <!-- Unknown matches to a set of conservative rules for the code analysis-->
 | 
			
		||||
    <PlatformToolset>Unknown</PlatformToolset>
 | 
			
		||||
    <LocalDebuggerCommand Condition="'$(LocalDebuggerCommand)' == ''">$(NMakeOutput)</LocalDebuggerCommand>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <!-- Build/Rebuild/Clean targets for NMake are defined in MSVC, so we need to provide them, when using MSBuild without MSVC targets -->
 | 
			
		||||
  <Target Name="Build">
 | 
			
		||||
    <Exec Command="$(NMakeBuildCommandLine)"/>
 | 
			
		||||
  </Target>
 | 
			
		||||
  <Target Name="Rebuild">
 | 
			
		||||
    <Exec Command="$(NMakeReBuildCommandLine)"/>
 | 
			
		||||
  </Target>
 | 
			
		||||
  <Target Name="Clean">
 | 
			
		||||
    <Exec Command="$(NMakeCleanCommandLine)"/>
 | 
			
		||||
  </Target>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<Project ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
			
		||||
  <PropertyGroup Condition="'$(GodotConfiguration)|$(GodotPlatform)'=='%%VSCONF%%'">
 | 
			
		||||
  <PropertyGroup Condition="%%CONDITION%%">
 | 
			
		||||
    <NMakeBuildCommandLine>%%BUILD%%</NMakeBuildCommandLine>
 | 
			
		||||
    <NMakeReBuildCommandLine>%%REBUILD%%</NMakeReBuildCommandLine>
 | 
			
		||||
    <NMakeCleanCommandLine>%%CLEAN%%</NMakeCleanCommandLine>
 | 
			
		||||
@@ -18,6 +18,9 @@
 | 
			
		||||
  <ItemGroup Condition="%%CONDITION%%">
 | 
			
		||||
    %%EXTRA_ITEMS%%
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <!-- Build/Rebuild/Clean targets for NMake are defined in MSVC, so we need to provide them, when using MSBuild without MSVC targets -->
 | 
			
		||||
  <Import Project="$(MSBuildProjectDirectory)\misc\msvs\nmake.substitution.props" Condition="%%CONDITION%% And !Exists('$(VCTargetsPath)\Microsoft.Cpp.targets')" />
 | 
			
		||||
</Project>
 | 
			
		||||
<!-- CHECKSUM
 | 
			
		||||
%%HASH%%
 | 
			
		||||
 
 | 
			
		||||
@@ -10,31 +10,32 @@
 | 
			
		||||
    <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  %%PROPERTIES%%
 | 
			
		||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
 | 
			
		||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.Default.props') "/>
 | 
			
		||||
  <PropertyGroup Label="Configuration">
 | 
			
		||||
    <ConfigurationType>Makefile</ConfigurationType>
 | 
			
		||||
    <UseOfMfc>false</UseOfMfc>
 | 
			
		||||
    <PlatformToolset>v143</PlatformToolset>
 | 
			
		||||
    <PlatformToolset>v143</PlatformToolset> <!--Might be overridden in the platform specific import or Microsoft.Cpp.$(GodotPlatform).user.props -->
 | 
			
		||||
    <DefaultPlatformToolset Condition="'$(DefaultPlatformToolset)'==''"/> <!--Workaround until https://youtrack.jetbrains.com/issue/RIDER-123783 is resolved. -->
 | 
			
		||||
    <OutDir>$(SolutionDir)\bin\$(GodotPlatform)\$(GodotConfiguration)\</OutDir>
 | 
			
		||||
    <IntDir>obj\$(GodotPlatform)\$(GodotConfiguration)\</IntDir>
 | 
			
		||||
    <LayoutDir>$(OutDir)\Layout</LayoutDir>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
 | 
			
		||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.props') "/>
 | 
			
		||||
  <ImportGroup Label="ExtensionSettings">
 | 
			
		||||
  </ImportGroup>
 | 
			
		||||
  <ImportGroup Label="PropertySheets">
 | 
			
		||||
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props')" Label="LocalAppDataPlatform" />
 | 
			
		||||
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props" Condition="Exists('$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props')" Label="LocalAppDataPlatform" />
 | 
			
		||||
  </ImportGroup>
 | 
			
		||||
  <PropertyGroup Label="UserMacros" />
 | 
			
		||||
  %%IMPORTS%%
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
 | 
			
		||||
    <ActiveProjectItemList></ActiveProjectItemList>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  %%IMPORTS%%
 | 
			
		||||
  <ItemGroup Condition="'$(IncludeListImported)'==''">
 | 
			
		||||
    %%DEFAULT_ITEMS%%
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
 | 
			
		||||
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.targets') "/>
 | 
			
		||||
  <ImportGroup Label="ExtensionTargets">
 | 
			
		||||
  </ImportGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								platform/linuxbsd/msvs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								platform/linuxbsd/msvs.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# Tuples with the name of the arch
 | 
			
		||||
def get_platforms():
 | 
			
		||||
    return [("x64", "x86_64")]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_configurations():
 | 
			
		||||
    return ["editor", "template_debug", "template_release"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_build_prefix(env):
 | 
			
		||||
    return []
 | 
			
		||||
							
								
								
									
										11
									
								
								platform/macos/msvs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								platform/macos/msvs.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# Tuples with the name of the arch
 | 
			
		||||
def get_platforms():
 | 
			
		||||
    return [("arm64", "arm64"), ("x64", "x86_64")]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_configurations():
 | 
			
		||||
    return ["editor", "template_debug", "template_release"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_build_prefix(env):
 | 
			
		||||
    return []
 | 
			
		||||
@@ -12,9 +12,13 @@ def get_configurations():
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_build_prefix(env):
 | 
			
		||||
    if not env.msvc:
 | 
			
		||||
        return []
 | 
			
		||||
    batch_file = methods.find_visual_c_batch_file(env)
 | 
			
		||||
    return [
 | 
			
		||||
        "cmd /V /C",
 | 
			
		||||
        "set "plat=$(PlatformTarget)"",
 | 
			
		||||
        "(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))",
 | 
			
		||||
        f"call "{batch_file}" !plat!",
 | 
			
		||||
        "^& (if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))",
 | 
			
		||||
        f"^& call "{batch_file}" !plat!",
 | 
			
		||||
        "^&",
 | 
			
		||||
    ]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user