Buildsystem improvements for the Mono module
- Make sure to search the mono installation directory for the right architecture in the windows registry. - Do not build GodotSharpTools directly to #bin dir. Instead build to the default output path and copy it. This way we avoid MSBuild adding files we don't want to #bin. - Add hint path for MSBuild in OSX. - Copy shared library on Unix if not statically linking. - Use vswhere to search MSBuild and search for 14.0 tools version in the registry instead of 4.0. - SCons will only fallback xbuild when msbuild is not found if 'xbuild_fallback=yes' is passed to the command. - Use mono's assembly path as FrameworkPathOverride if using with system's MSBuild (not mono's fork). - Cleanup.
This commit is contained in:
parent
4396712137
commit
9f469887fc
6 changed files with 341 additions and 115 deletions
|
@ -53,68 +53,149 @@ if env['tools']:
|
||||||
|
|
||||||
vars = Variables()
|
vars = Variables()
|
||||||
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
|
vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
|
||||||
|
vars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
|
||||||
vars.Update(env)
|
vars.Update(env)
|
||||||
|
|
||||||
# Glue sources
|
# Glue sources
|
||||||
if env['mono_glue']:
|
if env['mono_glue']:
|
||||||
env.add_source_files(env.modules_sources, 'glue/*.cpp')
|
env.add_source_files(env.modules_sources, 'glue/*.cpp')
|
||||||
else:
|
else:
|
||||||
env.Append(CPPDEFINES = [ 'MONO_GLUE_DISABLED' ])
|
env.Append(CPPDEFINES=['MONO_GLUE_DISABLED'])
|
||||||
|
|
||||||
if ARGUMENTS.get('yolo_copy', False):
|
if ARGUMENTS.get('yolo_copy', False):
|
||||||
env.Append(CPPDEFINES = [ 'YOLO_COPY' ])
|
env.Append(CPPDEFINES=['YOLO_COPY'])
|
||||||
|
|
||||||
|
|
||||||
# Build GodotSharpTools solution
|
# Build GodotSharpTools solution
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import mono_reg_utils as monoreg
|
|
||||||
|
def find_msbuild_unix(filename):
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
hint_dirs = ['/opt/novell/mono/bin']
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin'] + hint_dirs
|
||||||
|
|
||||||
|
for hint_dir in hint_dirs:
|
||||||
|
hint_path = os.path.join(hint_dir, filename)
|
||||||
|
if os.path.isfile(hint_path):
|
||||||
|
return hint_path
|
||||||
|
|
||||||
|
for hint_dir in os.environ["PATH"].split(os.pathsep):
|
||||||
|
hint_dir = hint_dir.strip('"')
|
||||||
|
hint_path = os.path.join(hint_dir, filename)
|
||||||
|
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
|
||||||
|
return hint_path
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_msbuild_windows():
|
||||||
|
import mono_reg_utils as monoreg
|
||||||
|
|
||||||
|
msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
|
||||||
|
|
||||||
|
if msbuild_tools_path:
|
||||||
|
return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), '')
|
||||||
|
else:
|
||||||
|
bits = env['bits']
|
||||||
|
|
||||||
|
if bits == '32':
|
||||||
|
if os.getenv('MONO32_PREFIX'):
|
||||||
|
mono_root = os.getenv('MONO32_PREFIX')
|
||||||
|
else:
|
||||||
|
mono_root = monoreg.find_mono_root_dir(bits)
|
||||||
|
else:
|
||||||
|
if os.getenv('MONO64_PREFIX'):
|
||||||
|
mono_root = os.getenv('MONO64_PREFIX')
|
||||||
|
else:
|
||||||
|
mono_root = monoreg.find_mono_root_dir(bits)
|
||||||
|
|
||||||
|
if mono_root:
|
||||||
|
msbuild_mono = os.path.join(mono_root, 'bin', 'msbuild.bat')
|
||||||
|
|
||||||
|
if os.path.isfile(msbuild_mono):
|
||||||
|
return (msbuild_mono, os.path.join(mono_root, 'lib', 'mono', '4.5'))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def mono_build_solution(source, target, env):
|
def mono_build_solution(source, target, env):
|
||||||
if os.name == 'nt':
|
import subprocess
|
||||||
msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
|
import mono_reg_utils as monoreg
|
||||||
if not msbuild_tools_path:
|
from shutil import copyfile
|
||||||
raise RuntimeError('Cannot find MSBuild Tools Path in the registry')
|
|
||||||
msbuild_path = os.path.join(msbuild_tools_path, 'MSBuild.exe')
|
|
||||||
else:
|
|
||||||
msbuild_path = 'msbuild'
|
|
||||||
|
|
||||||
output_path = os.path.abspath(os.path.join(str(target[0]), os.pardir))
|
framework_path_override = ''
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
msbuild_info = find_msbuild_windows()
|
||||||
|
if msbuild_info is None:
|
||||||
|
raise RuntimeError('Cannot find MSBuild executable')
|
||||||
|
msbuild_path = msbuild_windows[0]
|
||||||
|
framework_path_override = msbuild_windows[1]
|
||||||
|
else:
|
||||||
|
msbuild_path = find_msbuild_unix('msbuild')
|
||||||
|
if msbuild_path is None:
|
||||||
|
xbuild_fallback = env['xbuild_fallback']
|
||||||
|
|
||||||
|
if xbuild_fallback and os.name == 'nt':
|
||||||
|
print("Option 'xbuild_fallback' not supported on Windows")
|
||||||
|
xbuild_fallback = False
|
||||||
|
|
||||||
|
if xbuild_fallback:
|
||||||
|
print('Cannot find MSBuild executable, trying with xbuild')
|
||||||
|
print('Warning: xbuild is deprecated')
|
||||||
|
|
||||||
|
msbuild_path = find_msbuild_unix('xbuild')
|
||||||
|
|
||||||
|
if msbuild_path is None:
|
||||||
|
raise RuntimeError('Cannot find xbuild executable')
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Cannot find MSBuild executable')
|
||||||
|
|
||||||
|
print('MSBuild path: ' + msbuild_path)
|
||||||
|
|
||||||
|
build_config = 'Release'
|
||||||
|
|
||||||
msbuild_args = [
|
msbuild_args = [
|
||||||
msbuild_path,
|
msbuild_path,
|
||||||
os.path.abspath(str(source[0])),
|
os.path.abspath(str(source[0])),
|
||||||
'/p:Configuration=Release',
|
'/p:Configuration=' + build_config,
|
||||||
'/p:OutputPath=' + output_path
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if framework_path_override:
|
||||||
|
msbuild_args += ['/p:FrameworkPathOverride=' + framework_path_override]
|
||||||
|
|
||||||
msbuild_env = os.environ.copy()
|
msbuild_env = os.environ.copy()
|
||||||
|
|
||||||
# Needed when running from Developer Command Prompt for VS
|
# Needed when running from Developer Command Prompt for VS
|
||||||
if 'PLATFORM' in msbuild_env:
|
if 'PLATFORM' in msbuild_env:
|
||||||
del msbuild_env['PLATFORM']
|
del msbuild_env['PLATFORM']
|
||||||
|
|
||||||
msbuild_alt_paths = [ 'xbuild' ]
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(msbuild_args, env = msbuild_env)
|
subprocess.check_call(msbuild_args, env=msbuild_env)
|
||||||
break
|
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
raise RuntimeError('GodotSharpTools build failed')
|
raise RuntimeError('GodotSharpTools build failed')
|
||||||
except OSError:
|
|
||||||
if os.name != 'nt':
|
src_dir = os.path.abspath(os.path.join(str(source[0]), os.pardir, 'bin', build_config))
|
||||||
if not msbuild_alt_paths:
|
dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
|
||||||
raise RuntimeError('Could not find commands msbuild or xbuild')
|
|
||||||
# Try xbuild
|
if not os.path.isdir(dst_dir):
|
||||||
msbuild_args[0] = msbuild_alt_paths.pop(0)
|
if os.path.exists(dst_dir):
|
||||||
else:
|
raise RuntimeError('Target directory is a file')
|
||||||
raise RuntimeError('Could not find command MSBuild.exe')
|
os.makedirs(dst_dir)
|
||||||
|
|
||||||
|
asm_file = 'GodotSharpTools.dll'
|
||||||
|
|
||||||
|
copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
|
||||||
|
|
||||||
|
|
||||||
mono_sln_builder = Builder(action = mono_build_solution)
|
mono_sln_builder = Builder(action = mono_build_solution)
|
||||||
env.Append(BUILDERS = { 'MonoBuildSolution' : mono_sln_builder })
|
env.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder})
|
||||||
env.MonoBuildSolution(
|
env.MonoBuildSolution(
|
||||||
os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'),
|
os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'),
|
||||||
'editor/GodotSharpTools/GodotSharpTools.sln'
|
'editor/GodotSharpTools/GodotSharpTools.sln'
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import imp
|
import imp
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from shutil import copyfile
|
|
||||||
|
|
||||||
from SCons.Script import BoolVariable, Environment, Variables
|
from SCons.Script import BoolVariable, Environment, Variables
|
||||||
|
|
||||||
|
@ -16,8 +15,7 @@ def find_file_in_dir(directory, files, prefix='', extension=''):
|
||||||
for curfile in files:
|
for curfile in files:
|
||||||
if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
|
if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
|
||||||
return curfile
|
return curfile
|
||||||
|
return ''
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def can_build(platform):
|
def can_build(platform):
|
||||||
|
@ -31,6 +29,22 @@ def is_enabled():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def copy_file_no_replace(src_dir, dst_dir, name):
|
||||||
|
from shutil import copyfile
|
||||||
|
|
||||||
|
src_path = os.path.join(src_dir, name)
|
||||||
|
dst_path = os.path.join(dst_dir, name)
|
||||||
|
need_copy = True
|
||||||
|
|
||||||
|
if not os.path.isdir(dst_dir):
|
||||||
|
os.mkdir(dst_dir)
|
||||||
|
elif os.path.exists(dst_path):
|
||||||
|
need_copy = False
|
||||||
|
|
||||||
|
if need_copy:
|
||||||
|
copyfile(src_path, dst_path)
|
||||||
|
|
||||||
|
|
||||||
def configure(env):
|
def configure(env):
|
||||||
env.use_ptrcall = True
|
env.use_ptrcall = True
|
||||||
|
|
||||||
|
@ -38,6 +52,8 @@ def configure(env):
|
||||||
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
|
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
|
||||||
envvars.Update(env)
|
envvars.Update(env)
|
||||||
|
|
||||||
|
bits = env['bits']
|
||||||
|
|
||||||
mono_static = env['mono_static']
|
mono_static = env['mono_static']
|
||||||
|
|
||||||
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
|
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
|
||||||
|
@ -46,18 +62,18 @@ def configure(env):
|
||||||
if mono_static:
|
if mono_static:
|
||||||
raise RuntimeError('mono-static: Not supported on Windows')
|
raise RuntimeError('mono-static: Not supported on Windows')
|
||||||
|
|
||||||
if env['bits'] == '32':
|
if bits == '32':
|
||||||
if os.getenv('MONO32_PREFIX'):
|
if os.getenv('MONO32_PREFIX'):
|
||||||
mono_root = os.getenv('MONO32_PREFIX')
|
mono_root = os.getenv('MONO32_PREFIX')
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
mono_root = monoreg.find_mono_root_dir()
|
mono_root = monoreg.find_mono_root_dir(bits)
|
||||||
else:
|
else:
|
||||||
if os.getenv('MONO64_PREFIX'):
|
if os.getenv('MONO64_PREFIX'):
|
||||||
mono_root = os.getenv('MONO64_PREFIX')
|
mono_root = os.getenv('MONO64_PREFIX')
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
mono_root = monoreg.find_mono_root_dir()
|
mono_root = monoreg.find_mono_root_dir(bits)
|
||||||
|
|
||||||
if mono_root is None:
|
if not mono_root:
|
||||||
raise RuntimeError('Mono installation directory not found')
|
raise RuntimeError('Mono installation directory not found')
|
||||||
|
|
||||||
mono_lib_path = os.path.join(mono_root, 'lib')
|
mono_lib_path = os.path.join(mono_root, 'lib')
|
||||||
|
@ -67,7 +83,7 @@ def configure(env):
|
||||||
|
|
||||||
mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
|
mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
|
||||||
|
|
||||||
if mono_lib_name is None:
|
if not mono_lib_name:
|
||||||
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
|
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
|
||||||
|
|
||||||
if os.getenv('VCINSTALLDIR'):
|
if os.getenv('VCINSTALLDIR'):
|
||||||
|
@ -79,28 +95,23 @@ def configure(env):
|
||||||
|
|
||||||
mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
|
mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
|
||||||
|
|
||||||
mono_dll_src = os.path.join(mono_bin_path, mono_dll_name + '.dll')
|
if not mono_dll_name:
|
||||||
mono_dll_dst = os.path.join('bin', mono_dll_name + '.dll')
|
raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
|
||||||
copy_mono_dll = True
|
|
||||||
|
|
||||||
if not os.path.isdir('bin'):
|
copy_file_no_replace(mono_bin_path, 'bin', mono_dll_name + '.dll')
|
||||||
os.mkdir('bin')
|
|
||||||
elif os.path.exists(mono_dll_dst):
|
|
||||||
copy_mono_dll = False
|
|
||||||
|
|
||||||
if copy_mono_dll:
|
|
||||||
copyfile(mono_dll_src, mono_dll_dst)
|
|
||||||
else:
|
else:
|
||||||
mono_root = None
|
sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so'
|
||||||
|
|
||||||
if env['bits'] == '32':
|
mono_root = ''
|
||||||
|
|
||||||
|
if bits == '32':
|
||||||
if os.getenv('MONO32_PREFIX'):
|
if os.getenv('MONO32_PREFIX'):
|
||||||
mono_root = os.getenv('MONO32_PREFIX')
|
mono_root = os.getenv('MONO32_PREFIX')
|
||||||
else:
|
else:
|
||||||
if os.getenv('MONO64_PREFIX'):
|
if os.getenv('MONO64_PREFIX'):
|
||||||
mono_root = os.getenv('MONO64_PREFIX')
|
mono_root = os.getenv('MONO64_PREFIX')
|
||||||
|
|
||||||
if mono_root is not None:
|
if mono_root:
|
||||||
mono_lib_path = os.path.join(mono_root, 'lib')
|
mono_lib_path = os.path.join(mono_root, 'lib')
|
||||||
|
|
||||||
env.Append(LIBPATH=mono_lib_path)
|
env.Append(LIBPATH=mono_lib_path)
|
||||||
|
@ -108,7 +119,7 @@ def configure(env):
|
||||||
|
|
||||||
mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
|
mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
|
||||||
|
|
||||||
if mono_lib is None:
|
if not mono_lib:
|
||||||
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
|
raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
|
||||||
|
|
||||||
env.Append(CPPFLAGS=['-D_REENTRANT'])
|
env.Append(CPPFLAGS=['-D_REENTRANT'])
|
||||||
|
@ -130,12 +141,37 @@ def configure(env):
|
||||||
elif sys.platform == "linux" or sys.platform == "linux2":
|
elif sys.platform == "linux" or sys.platform == "linux2":
|
||||||
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
|
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
|
||||||
|
|
||||||
|
if not mono_static:
|
||||||
|
mono_so_name = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension=sharedlib_ext)
|
||||||
|
|
||||||
|
if not mono_so_name:
|
||||||
|
raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
|
||||||
|
|
||||||
|
copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
|
||||||
else:
|
else:
|
||||||
if mono_static:
|
if mono_static:
|
||||||
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
|
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
|
||||||
|
|
||||||
env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
|
env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
|
||||||
|
|
||||||
|
mono_lib_path = ''
|
||||||
|
mono_so_name = ''
|
||||||
|
|
||||||
|
tmpenv = Environment()
|
||||||
|
tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
|
||||||
|
|
||||||
|
for hint_dir in tmpenv['LIBPATH']:
|
||||||
|
name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
|
||||||
|
if name_found:
|
||||||
|
mono_lib_path = hint_dir
|
||||||
|
mono_so_name = name_found
|
||||||
|
break
|
||||||
|
|
||||||
|
if not mono_so_name:
|
||||||
|
raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
|
||||||
|
|
||||||
|
copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
|
||||||
|
|
||||||
env.Append(LINKFLAGS='-rdynamic')
|
env.Append(LINKFLAGS='-rdynamic')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using Microsoft.Build.Framework;
|
using Microsoft.Build.Framework;
|
||||||
|
|
||||||
|
@ -12,23 +13,37 @@ namespace GodotSharpTools.Build
|
||||||
public class BuildInstance : IDisposable
|
public class BuildInstance : IDisposable
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
|
private extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal extern static string godot_icall_BuildInstance_get_MSBuildPath();
|
private extern static MSBuildInfo godot_icall_BuildInstance_get_MSBuildInfo();
|
||||||
|
|
||||||
private static string MSBuildPath
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct MSBuildInfo
|
||||||
{
|
{
|
||||||
get
|
string path;
|
||||||
{
|
string frameworkPathOverride;
|
||||||
string ret = godot_icall_BuildInstance_get_MSBuildPath();
|
|
||||||
|
|
||||||
if (ret == null)
|
public string MSBuildPath
|
||||||
|
{
|
||||||
|
get { return path; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FrameworkPathOverride
|
||||||
|
{
|
||||||
|
get { return frameworkPathOverride; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MSBuildInfo GetMSBuildInfo()
|
||||||
|
{
|
||||||
|
MSBuildInfo ret = godot_icall_BuildInstance_get_MSBuildInfo();
|
||||||
|
|
||||||
|
if (ret.MSBuildPath == null)
|
||||||
throw new FileNotFoundException("Cannot find the MSBuild executable.");
|
throw new FileNotFoundException("Cannot find the MSBuild executable.");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private string solution;
|
private string solution;
|
||||||
private string config;
|
private string config;
|
||||||
|
@ -48,9 +63,19 @@ namespace GodotSharpTools.Build
|
||||||
|
|
||||||
public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
|
public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
|
||||||
{
|
{
|
||||||
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties);
|
MSBuildInfo msbuildInfo = GetMSBuildInfo();
|
||||||
|
|
||||||
ProcessStartInfo startInfo = new ProcessStartInfo(MSBuildPath, compilerArgs);
|
List<string> customPropertiesList = new List<string>();
|
||||||
|
|
||||||
|
if (customProperties != null)
|
||||||
|
customPropertiesList.AddRange(customProperties);
|
||||||
|
|
||||||
|
if (msbuildInfo.FrameworkPathOverride.Length > 0)
|
||||||
|
customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.FrameworkPathOverride);
|
||||||
|
|
||||||
|
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
|
||||||
|
|
||||||
|
ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.MSBuildPath, compilerArgs);
|
||||||
|
|
||||||
// No console output, thanks
|
// No console output, thanks
|
||||||
startInfo.RedirectStandardOutput = true;
|
startInfo.RedirectStandardOutput = true;
|
||||||
|
@ -82,9 +107,19 @@ namespace GodotSharpTools.Build
|
||||||
if (process != null)
|
if (process != null)
|
||||||
throw new InvalidOperationException("Already in use");
|
throw new InvalidOperationException("Already in use");
|
||||||
|
|
||||||
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customProperties);
|
MSBuildInfo msbuildInfo = GetMSBuildInfo();
|
||||||
|
|
||||||
ProcessStartInfo startInfo = new ProcessStartInfo("msbuild", compilerArgs);
|
List<string> customPropertiesList = new List<string>();
|
||||||
|
|
||||||
|
if (customProperties != null)
|
||||||
|
customPropertiesList.AddRange(customProperties);
|
||||||
|
|
||||||
|
if (msbuildInfo.FrameworkPathOverride.Length > 0)
|
||||||
|
customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.FrameworkPathOverride);
|
||||||
|
|
||||||
|
string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
|
||||||
|
|
||||||
|
ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.MSBuildPath, compilerArgs);
|
||||||
|
|
||||||
// No console output, thanks
|
// No console output, thanks
|
||||||
startInfo.RedirectStandardOutput = true;
|
startInfo.RedirectStandardOutput = true;
|
||||||
|
@ -101,10 +136,13 @@ namespace GodotSharpTools.Build
|
||||||
|
|
||||||
process.Start();
|
process.Start();
|
||||||
|
|
||||||
|
process.BeginOutputReadLine();
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties)
|
private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, List<string> customProperties)
|
||||||
{
|
{
|
||||||
string arguments = string.Format(@"""{0}"" /v:normal /t:Build ""/p:{1}"" ""/l:{2},{3};{4}""",
|
string arguments = string.Format(@"""{0}"" /v:normal /t:Build ""/p:{1}"" ""/l:{2},{3};{4}""",
|
||||||
solution,
|
solution,
|
||||||
|
@ -114,12 +152,9 @@ namespace GodotSharpTools.Build
|
||||||
loggerOutputDir
|
loggerOutputDir
|
||||||
);
|
);
|
||||||
|
|
||||||
if (customProperties != null)
|
|
||||||
{
|
|
||||||
foreach (string customProperty in customProperties)
|
foreach (string customProperty in customProperties)
|
||||||
{
|
{
|
||||||
arguments += " /p:" + customProperty;
|
arguments += " \"/p:" + customProperty + "\"";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return arguments;
|
return arguments;
|
||||||
|
|
|
@ -71,10 +71,15 @@ String _find_build_engine_on_unix(const String &p_name) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
|
MonoString **godot_icall_BuildInstance_get_MSBuildInfo() {
|
||||||
|
|
||||||
GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
|
GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
|
||||||
|
|
||||||
|
MonoString *res[2] = {
|
||||||
|
NULL, // MSBuildPath
|
||||||
|
NULL // FrameworkPathOverride
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(WINDOWS_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
switch (build_tool) {
|
switch (build_tool) {
|
||||||
case GodotSharpBuilds::MSBUILD: {
|
case GodotSharpBuilds::MSBUILD: {
|
||||||
|
@ -84,11 +89,17 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
|
||||||
if (!msbuild_tools_path.ends_with("\\"))
|
if (!msbuild_tools_path.ends_with("\\"))
|
||||||
msbuild_tools_path += "\\";
|
msbuild_tools_path += "\\";
|
||||||
|
|
||||||
return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
|
res[0] = GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
|
||||||
|
|
||||||
|
// FrameworkPathOverride
|
||||||
|
res[1] = GDMonoMarshal::mono_string_from_godot(GDMono::get_singleton()->get_mono_reg_info().assembly_dir);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (OS::get_singleton()->is_stdout_verbose())
|
||||||
OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n");
|
OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n");
|
||||||
}
|
} // fall through
|
||||||
case GodotSharpBuilds::MSBUILD_MONO: {
|
case GodotSharpBuilds::MSBUILD_MONO: {
|
||||||
String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
|
String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
|
||||||
|
|
||||||
|
@ -96,17 +107,9 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
|
||||||
WARN_PRINTS("Cannot find msbuild ('mono/builds/build_tool'). Tried with path: " + msbuild_path);
|
WARN_PRINTS("Cannot find msbuild ('mono/builds/build_tool'). Tried with path: " + msbuild_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GDMonoMarshal::mono_string_from_godot(msbuild_path);
|
res[0] = GDMonoMarshal::mono_string_from_godot(msbuild_path);
|
||||||
}
|
return res;
|
||||||
case GodotSharpBuilds::XBUILD: {
|
} break;
|
||||||
String xbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("xbuild.bat");
|
|
||||||
|
|
||||||
if (!FileAccess::exists(xbuild_path)) {
|
|
||||||
WARN_PRINTS("Cannot find xbuild ('mono/builds/build_tool'). Tried with path: " + xbuild_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GDMonoMarshal::mono_string_from_godot(xbuild_path);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
ERR_EXPLAIN("You don't deserve to live");
|
ERR_EXPLAIN("You don't deserve to live");
|
||||||
CRASH_NOW();
|
CRASH_NOW();
|
||||||
|
@ -118,25 +121,26 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
|
||||||
if (build_tool != GodotSharpBuilds::XBUILD) {
|
if (build_tool != GodotSharpBuilds::XBUILD) {
|
||||||
if (msbuild_path.empty()) {
|
if (msbuild_path.empty()) {
|
||||||
WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool').");
|
WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool').");
|
||||||
return NULL;
|
return res;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (xbuild_path.empty()) {
|
if (xbuild_path.empty()) {
|
||||||
WARN_PRINT("Cannot find xbuild ('mono/builds/build_tool').");
|
WARN_PRINT("Cannot find xbuild ('mono/builds/build_tool').");
|
||||||
return NULL;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
|
res[0] = GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
|
||||||
|
return res;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return res;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotSharpBuilds::_register_internal_calls() {
|
void GodotSharpBuilds::_register_internal_calls() {
|
||||||
|
|
||||||
mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback);
|
mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback);
|
||||||
mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildPath", (void *)godot_icall_BuildInstance_get_MSBuildPath);
|
mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildInfo", (void *)godot_icall_BuildInstance_get_MSBuildInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
|
void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
|
||||||
|
@ -353,9 +357,22 @@ GodotSharpBuilds::GodotSharpBuilds() {
|
||||||
// Build tool settings
|
// Build tool settings
|
||||||
EditorSettings *ed_settings = EditorSettings::get_singleton();
|
EditorSettings *ed_settings = EditorSettings::get_singleton();
|
||||||
if (!ed_settings->has_setting("mono/builds/build_tool")) {
|
if (!ed_settings->has_setting("mono/builds/build_tool")) {
|
||||||
ed_settings->set_setting("mono/builds/build_tool", MSBUILD);
|
ed_settings->set_setting("mono/builds/build_tool",
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
// TODO: Default to MSBUILD_MONO if its csc.exe issue is fixed in the installed mono version
|
||||||
|
MSBUILD
|
||||||
|
#else
|
||||||
|
MSBUILD_MONO
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM, "MSBuild (System),MSBuild (Mono),xbuild"));
|
ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM,
|
||||||
|
#ifdef WINDOWS_ENABLED
|
||||||
|
"MSBuild (Mono),MSBuild (System)"
|
||||||
|
#else
|
||||||
|
"MSBuild (Mono),xbuild (Deprecated)"
|
||||||
|
#endif
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
GodotSharpBuilds::~GodotSharpBuilds() {
|
GodotSharpBuilds::~GodotSharpBuilds() {
|
||||||
|
|
|
@ -67,9 +67,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BuildTool {
|
enum BuildTool {
|
||||||
MSBUILD,
|
|
||||||
MSBUILD_MONO,
|
MSBUILD_MONO,
|
||||||
XBUILD
|
#ifdef WINDOWS_ENABLED
|
||||||
|
MSBUILD
|
||||||
|
#else
|
||||||
|
XBUILD // Deprecated
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
_FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }
|
_FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
import sys
|
import sys
|
||||||
|
@ -11,8 +12,7 @@ if os.name == 'nt':
|
||||||
def _reg_open_key(key, subkey):
|
def _reg_open_key(key, subkey):
|
||||||
try:
|
try:
|
||||||
return winreg.OpenKey(key, subkey)
|
return winreg.OpenKey(key, subkey)
|
||||||
except (WindowsError, EnvironmentError) as e:
|
except WindowsError, OSError:
|
||||||
import platform
|
|
||||||
if platform.architecture()[0] == '32bit':
|
if platform.architecture()[0] == '32bit':
|
||||||
bitness_sam = winreg.KEY_WOW64_64KEY
|
bitness_sam = winreg.KEY_WOW64_64KEY
|
||||||
else:
|
else:
|
||||||
|
@ -20,39 +20,93 @@ def _reg_open_key(key, subkey):
|
||||||
return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
|
return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
|
||||||
|
|
||||||
|
|
||||||
def _find_mono_in_reg(subkey):
|
def _reg_open_key_bits(key, subkey, bits):
|
||||||
|
sam = winreg.KEY_READ
|
||||||
|
|
||||||
|
if platform.architecture()[0] == '32bit':
|
||||||
|
if bits == '64':
|
||||||
|
# Force 32bit process to search in 64bit registry
|
||||||
|
sam |= winreg.KEY_WOW64_64KEY
|
||||||
|
else:
|
||||||
|
if bits == '32':
|
||||||
|
# Force 64bit process to search in 32bit registry
|
||||||
|
sam |= winreg.KEY_WOW64_32KEY
|
||||||
|
|
||||||
|
return winreg.OpenKey(key, subkey, 0, sam)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_mono_in_reg(subkey, bits):
|
||||||
try:
|
try:
|
||||||
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
|
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
|
||||||
value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
|
value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
|
||||||
return value
|
return value
|
||||||
except (WindowsError, EnvironmentError) as e:
|
except WindowsError, OSError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _find_mono_in_reg_old(subkey):
|
|
||||||
|
def _find_mono_in_reg_old(subkey, bits):
|
||||||
try:
|
try:
|
||||||
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
|
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
|
||||||
default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
|
default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
|
||||||
if default_clr:
|
if default_clr:
|
||||||
return _find_mono_in_reg(subkey + '\\' + default_clr)
|
return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
|
||||||
return None
|
return None
|
||||||
except (WindowsError, EnvironmentError):
|
except (WindowsError, EnvironmentError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def find_mono_root_dir():
|
def find_mono_root_dir(bits):
|
||||||
dir = _find_mono_in_reg(r'SOFTWARE\Mono')
|
root_dir = _find_mono_in_reg(r'SOFTWARE\Mono', bits)
|
||||||
if dir:
|
if root_dir is not None:
|
||||||
return dir
|
return root_dir
|
||||||
dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono')
|
root_dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono', bits)
|
||||||
if dir:
|
if root_dir is not None:
|
||||||
return dir
|
return root_dir
|
||||||
return None
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def find_msbuild_tools_path_reg():
|
def find_msbuild_tools_path_reg():
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
vswhere = os.getenv('PROGRAMFILES(X86)')
|
||||||
|
if not vswhere:
|
||||||
|
vswhere = os.getenv('PROGRAMFILES')
|
||||||
|
vswhere += r'\Microsoft Visual Studio\Installer\vswhere.exe'
|
||||||
|
|
||||||
|
vswhere_args = ['-latest', '-requires', 'Microsoft.Component.MSBuild']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0') as hKey:
|
lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
parts = line.split(':', 1)
|
||||||
|
|
||||||
|
if len(parts) < 2 or parts[0] != 'installationPath':
|
||||||
|
continue
|
||||||
|
|
||||||
|
val = parts[1].strip()
|
||||||
|
|
||||||
|
if not val:
|
||||||
|
raise ValueError('Value of `installationPath` entry is empty')
|
||||||
|
|
||||||
|
return os.path.join(val, "MSBuild\\15.0\\Bin")
|
||||||
|
|
||||||
|
raise ValueError('Cannot find `installationPath` entry')
|
||||||
|
except ValueError as e:
|
||||||
|
print('Error reading output from vswhere: ' + e.message)
|
||||||
|
except WindowsError:
|
||||||
|
pass # Fine, vswhere not found
|
||||||
|
except subprocess.CalledProcessError, OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Try to find 14.0 in the Registry
|
||||||
|
|
||||||
|
try:
|
||||||
|
subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
|
||||||
|
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
|
||||||
value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
|
value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
|
||||||
return value
|
return value
|
||||||
except (WindowsError, EnvironmentError) as e:
|
except WindowsError, OSError:
|
||||||
return None
|
return ''
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
Loading…
Reference in a new issue