Skip to content

Commit 4362b11

Browse files
committed
Merge pull request #103405 from van800/shakhov/macosx
Fix `.sln` project generation logic for Rider to support all OS and all C++ toolchains
2 parents d7ced73 + 6ff86e4 commit 4362b11

File tree

8 files changed

+137
-36
lines changed

8 files changed

+137
-36
lines changed

.editorconfig

+4
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ indent_style = space
1515
[{*.{yml,yaml},.clang{-format,-tidy,d}}]
1616
indent_size = 2
1717
indent_style = space
18+
19+
[{*.props,*.vcxproj}]
20+
indent_size = 2
21+
indent_style = space

methods.py

+75-27
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from typing import Generator, List, Optional, Union, cast
1515

1616
from misc.utility.color import print_error, print_info, print_warning
17+
from platform_methods import detect_arch
1718

1819
# Get the "Godot" folder name ahead of time
1920
base_folder = Path(__file__).resolve().parent
@@ -1055,8 +1056,22 @@ def get_dependencies(file, env, exts, headers, sources, others):
10551056
platform = env["platform"]
10561057
target = env["target"]
10571058
arch = env["arch"]
1059+
host_arch = detect_arch()
1060+
1061+
host_platform = "windows"
1062+
if (
1063+
sys.platform.startswith("linux")
1064+
or sys.platform.startswith("dragonfly")
1065+
or sys.platform.startswith("freebsd")
1066+
or sys.platform.startswith("netbsd")
1067+
or sys.platform.startswith("openbsd")
1068+
):
1069+
host_platform = "linuxbsd"
1070+
elif sys.platform == "darwin":
1071+
host_platform = "macos"
10581072

10591073
vs_configuration = {}
1074+
host_vs_configuration = {}
10601075
common_build_prefix = []
10611076
confs = []
10621077
for x in sorted(glob.glob("platform/*")):
@@ -1085,6 +1100,12 @@ def get_dependencies(file, env, exts, headers, sources, others):
10851100
if platform == platform_name:
10861101
common_build_prefix = msvs.get_build_prefix(env)
10871102
vs_configuration = vsconf
1103+
if platform_name == host_platform:
1104+
host_vs_configuration = vsconf
1105+
for a in vsconf["arches"]:
1106+
if host_arch == a["architecture"]:
1107+
host_arch = a["platform"]
1108+
break
10881109
except Exception:
10891110
pass
10901111

@@ -1242,12 +1263,11 @@ def get_dependencies(file, env, exts, headers, sources, others):
12421263
properties.append(
12431264
"<ActiveProjectItemList_%s>;%s;</ActiveProjectItemList_%s>" % (x, ";".join(itemlist[x]), x)
12441265
)
1245-
output = f"bin\\godot{env['PROGSUFFIX']}"
1266+
output = os.path.join("bin", f"godot{env['PROGSUFFIX']}")
12461267

12471268
with open("misc/msvs/props.template", "r", encoding="utf-8") as file:
12481269
props_template = file.read()
12491270

1250-
props_template = props_template.replace("%%VSCONF%%", vsconf)
12511271
props_template = props_template.replace("%%CONDITION%%", condition)
12521272
props_template = props_template.replace("%%PROPERTIES%%", "\n ".join(properties))
12531273
props_template = props_template.replace("%%EXTRA_ITEMS%%", "\n ".join(extraItems))
@@ -1260,6 +1280,7 @@ def get_dependencies(file, env, exts, headers, sources, others):
12601280

12611281
proplist = [str(j) for j in env["CPPPATH"]]
12621282
proplist += [str(j) for j in env.get("VSHINT_INCLUDES", [])]
1283+
proplist += [str(j) for j in get_default_include_paths(env)]
12631284
props_template = props_template.replace("%%INCLUDES%%", ";".join(proplist))
12641285

12651286
proplist = env["CCFLAGS"]
@@ -1295,17 +1316,17 @@ def get_dependencies(file, env, exts, headers, sources, others):
12951316

12961317
commands = "scons"
12971318
if len(common_build_prefix) == 0:
1298-
commands = "echo Starting SCons &amp;&amp; cmd /V /C " + commands
1319+
commands = "echo Starting SCons &amp; " + commands
12991320
else:
1300-
common_build_prefix[0] = "echo Starting SCons &amp;&amp; cmd /V /C " + common_build_prefix[0]
1321+
common_build_prefix[0] = "echo Starting SCons &amp; " + common_build_prefix[0]
13011322

1302-
cmd = " ^&amp; ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
1323+
cmd = " ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
13031324
props_template = props_template.replace("%%BUILD%%", cmd)
13041325

1305-
cmd = " ^&amp; ".join(common_build_prefix + [" ".join([commands] + cmd_rebuild)])
1326+
cmd = " ".join(common_build_prefix + [" ".join([commands] + cmd_rebuild)])
13061327
props_template = props_template.replace("%%REBUILD%%", cmd)
13071328

1308-
cmd = " ^&amp; ".join(common_build_prefix + [" ".join([commands] + cmd_clean)])
1329+
cmd = " ".join(common_build_prefix + [" ".join([commands] + cmd_clean)])
13091330
props_template = props_template.replace("%%CLEAN%%", cmd)
13101331

13111332
with open(
@@ -1336,18 +1357,45 @@ def get_dependencies(file, env, exts, headers, sources, others):
13361357
section2 = []
13371358
for conf in confs:
13381359
godot_platform = conf["platform"]
1360+
has_editor = "editor" in conf["targets"]
1361+
1362+
# Skip any platforms that can build the editor and don't match the host platform.
1363+
#
1364+
# When both Windows and Mac define an editor target, it's defined as platform+target+arch (windows+editor+x64 for example).
1365+
# VS only supports two attributes, a "Configuration" and a "Platform", and we currently map our target to the Configuration
1366+
# (i.e. editor/template_debug/template_release), and our architecture to the "Platform" (i.e. x64, arm64, etc).
1367+
# Those two are not enough to disambiguate multiple godot targets for different godot platforms with the same architecture,
1368+
# i.e. editor|x64 would currently match both windows editor intel 64 and linux editor intel 64.
1369+
#
1370+
# TODO: More work is needed in order to support generating VS projects that unambiguously support all platform+target+arch variations.
1371+
# 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.
1372+
if has_editor and godot_platform != host_vs_configuration["platform"]:
1373+
continue
1374+
13391375
for p in conf["arches"]:
13401376
sln_plat = p["platform"]
13411377
proj_plat = sln_plat
13421378
godot_arch = p["architecture"]
13431379

1344-
# Redirect editor configurations for non-Windows platforms to the Windows one, so the solution has all the permutations
1345-
# and VS doesn't complain about missing project configurations.
1380+
# Redirect editor configurations for platforms that don't support the editor target to the default editor target on the
1381+
# active host platform, so the solution has all the permutations and VS doesn't complain about missing project configurations.
13461382
# These configurations are disabled, so they show up but won't build.
1347-
if godot_platform != "windows":
1383+
if not has_editor:
13481384
section1 += [f"editor|{sln_plat} = editor|{proj_plat}"]
1349-
section2 += [
1350-
f"{{{proj_uuid}}}.editor|{proj_plat}.ActiveCfg = editor|{proj_plat}",
1385+
section2 += [f"{{{proj_uuid}}}.editor|{proj_plat}.ActiveCfg = editor|{host_arch}"]
1386+
1387+
configurations += [
1388+
f'<ProjectConfiguration Include="editor|{proj_plat}">',
1389+
" <Configuration>editor</Configuration>",
1390+
f" <Platform>{proj_plat}</Platform>",
1391+
"</ProjectConfiguration>",
1392+
]
1393+
1394+
properties += [
1395+
f"<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='editor|{proj_plat}'\">",
1396+
" <GodotConfiguration>editor</GodotConfiguration>",
1397+
f" <GodotPlatform>{proj_plat}</GodotPlatform>",
1398+
"</PropertyGroup>",
13511399
]
13521400

13531401
for t in conf["targets"]:
@@ -1371,21 +1419,6 @@ def get_dependencies(file, env, exts, headers, sources, others):
13711419
"</PropertyGroup>",
13721420
]
13731421

1374-
if godot_platform != "windows":
1375-
configurations += [
1376-
f'<ProjectConfiguration Include="editor|{proj_plat}">',
1377-
" <Configuration>editor</Configuration>",
1378-
f" <Platform>{proj_plat}</Platform>",
1379-
"</ProjectConfiguration>",
1380-
]
1381-
1382-
properties += [
1383-
f"<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='editor|{proj_plat}'\">",
1384-
" <GodotConfiguration>editor</GodotConfiguration>",
1385-
f" <GodotPlatform>{proj_plat}</GodotPlatform>",
1386-
"</PropertyGroup>",
1387-
]
1388-
13891422
p = f"{project_name}.{godot_platform}.{godot_target}.{godot_arch}.generated.props"
13901423
imports += [
13911424
f'<Import Project="$(MSBuildProjectDirectory)\\{p}" Condition="Exists(\'$(MSBuildProjectDirectory)\\{p}\')"/>'
@@ -1594,3 +1627,18 @@ def to_raw_cstring(value: Union[str, List[str]]) -> str:
15941627
else:
15951628
# Wrap multiple segments in parenthesis to suppress `string-concatenation` warnings on clang.
15961629
return "({})".format(" ".join(f'R"<!>({segment.decode()})<!>"' for segment in split))
1630+
1631+
1632+
def get_default_include_paths(env):
1633+
if env.msvc:
1634+
return []
1635+
compiler = env.subst("$CXX")
1636+
target = os.path.join(env.Dir("#main").abspath, "main.cpp")
1637+
args = [compiler, target, "-x", "c++", "-v"]
1638+
ret = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
1639+
output = ret.stdout
1640+
match = re.search(r"#include <\.\.\.> search starts here:([\S\s]*)End of search list.", output)
1641+
if not match:
1642+
print_warning("Failed to find the include paths in the compiler output.")
1643+
return []
1644+
return [x.strip() for x in match[1].strip().splitlines()]

misc/msvs/nmake.substitution.props

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<!-- override the PlatformToolset, which is set in the godot.vcxproj-->
5+
<!-- Unknown matches to a set of conservative rules for the code analysis-->
6+
<PlatformToolset>Unknown</PlatformToolset>
7+
<LocalDebuggerCommand Condition="'$(LocalDebuggerCommand)' == ''">$(NMakeOutput)</LocalDebuggerCommand>
8+
</PropertyGroup>
9+
<!-- Build/Rebuild/Clean targets for NMake are defined in MSVC, so we need to provide them, when using MSBuild without MSVC targets -->
10+
<Target Name="Build">
11+
<Exec Command="$(NMakeBuildCommandLine)"/>
12+
</Target>
13+
<Target Name="Rebuild">
14+
<Exec Command="$(NMakeReBuildCommandLine)"/>
15+
</Target>
16+
<Target Name="Clean">
17+
<Exec Command="$(NMakeCleanCommandLine)"/>
18+
</Target>
19+
</Project>

misc/msvs/props.template

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3-
<PropertyGroup Condition="'$(GodotConfiguration)|$(GodotPlatform)'=='%%VSCONF%%'">
3+
<PropertyGroup Condition="%%CONDITION%%">
44
<NMakeBuildCommandLine>%%BUILD%%</NMakeBuildCommandLine>
55
<NMakeReBuildCommandLine>%%REBUILD%%</NMakeReBuildCommandLine>
66
<NMakeCleanCommandLine>%%CLEAN%%</NMakeCleanCommandLine>
@@ -18,6 +18,9 @@
1818
<ItemGroup Condition="%%CONDITION%%">
1919
%%EXTRA_ITEMS%%
2020
</ItemGroup>
21+
22+
<!-- Build/Rebuild/Clean targets for NMake are defined in MSVC, so we need to provide them, when using MSBuild without MSVC targets -->
23+
<Import Project="$(MSBuildProjectDirectory)\misc\msvs\nmake.substitution.props" Condition="%%CONDITION%% And !Exists('$(VCTargetsPath)\Microsoft.Cpp.targets')" />
2124
</Project>
2225
<!-- CHECKSUM
2326
%%HASH%%

misc/msvs/vcxproj.template

+7-6
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,32 @@
1010
<VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
1111
</PropertyGroup>
1212
%%PROPERTIES%%
13-
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
13+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.Default.props') "/>
1414
<PropertyGroup Label="Configuration">
1515
<ConfigurationType>Makefile</ConfigurationType>
1616
<UseOfMfc>false</UseOfMfc>
17-
<PlatformToolset>v143</PlatformToolset>
17+
<PlatformToolset>v143</PlatformToolset> <!--Might be overridden in the platform specific import or Microsoft.Cpp.$(GodotPlatform).user.props -->
18+
<DefaultPlatformToolset Condition="'$(DefaultPlatformToolset)'==''"/> <!--Workaround until https://youtrack.jetbrains.com/issue/RIDER-123783 is resolved. -->
1819
<OutDir>$(SolutionDir)\bin\$(GodotPlatform)\$(GodotConfiguration)\</OutDir>
1920
<IntDir>obj\$(GodotPlatform)\$(GodotConfiguration)\</IntDir>
2021
<LayoutDir>$(OutDir)\Layout</LayoutDir>
2122
</PropertyGroup>
22-
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
23+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.props') "/>
2324
<ImportGroup Label="ExtensionSettings">
2425
</ImportGroup>
2526
<ImportGroup Label="PropertySheets">
26-
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props')" Label="LocalAppDataPlatform" />
27+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props" Condition="Exists('$(UserRootDir)\Microsoft.Cpp.$(GodotPlatform).user.props')" Label="LocalAppDataPlatform" />
2728
</ImportGroup>
2829
<PropertyGroup Label="UserMacros" />
30+
%%IMPORTS%%
2931
<PropertyGroup>
3032
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
3133
<ActiveProjectItemList></ActiveProjectItemList>
3234
</PropertyGroup>
33-
%%IMPORTS%%
3435
<ItemGroup Condition="'$(IncludeListImported)'==''">
3536
%%DEFAULT_ITEMS%%
3637
</ItemGroup>
37-
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
38+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" Condition="Exists('$(VCTargetsPath)\Microsoft.Cpp.targets') "/>
3839
<ImportGroup Label="ExtensionTargets">
3940
</ImportGroup>
4041
</Project>

platform/linuxbsd/msvs.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Tuples with the name of the arch
2+
def get_platforms():
3+
return [("x64", "x86_64")]
4+
5+
6+
def get_configurations():
7+
return ["editor", "template_debug", "template_release"]
8+
9+
10+
def get_build_prefix(env):
11+
return []

platform/macos/msvs.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Tuples with the name of the arch
2+
def get_platforms():
3+
return [("arm64", "arm64"), ("x64", "x86_64")]
4+
5+
6+
def get_configurations():
7+
return ["editor", "template_debug", "template_release"]
8+
9+
10+
def get_build_prefix(env):
11+
return []

platform/windows/msvs.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ def get_configurations():
1212

1313

1414
def get_build_prefix(env):
15+
if not env.msvc:
16+
return []
1517
batch_file = methods.find_visual_c_batch_file(env)
1618
return [
19+
"cmd /V /C",
1720
"set &quot;plat=$(PlatformTarget)&quot;",
18-
"(if &quot;$(PlatformTarget)&quot;==&quot;x64&quot; (set &quot;plat=x86_amd64&quot;))",
19-
f"call &quot;{batch_file}&quot; !plat!",
21+
"^&amp; (if &quot;$(PlatformTarget)&quot;==&quot;x64&quot; (set &quot;plat=x86_amd64&quot;))",
22+
f"^&amp; call &quot;{batch_file}&quot; !plat!",
23+
"^&amp;",
2024
]

0 commit comments

Comments
 (0)