Skip to content

Commit

Permalink
Merge pull request #12388 from neikeq/r
Browse files Browse the repository at this point in the history
Buildsystem improvements for the Mono module
  • Loading branch information
neikeq authored Oct 29, 2017
2 parents 84edb58 + 9f46988 commit 09a1e11
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 113 deletions.
139 changes: 110 additions & 29 deletions modules/mono/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -53,68 +53,149 @@ if env['tools']:

vars = Variables()
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)

# Glue sources
if env['mono_glue']:
env.add_source_files(env.modules_sources, 'glue/*.cpp')
else:
env.Append(CPPDEFINES = [ 'MONO_GLUE_DISABLED' ])
env.Append(CPPDEFINES=['MONO_GLUE_DISABLED'])

if ARGUMENTS.get('yolo_copy', False):
env.Append(CPPDEFINES = [ 'YOLO_COPY' ])
env.Append(CPPDEFINES=['YOLO_COPY'])


# Build GodotSharpTools solution


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):
import subprocess
import mono_reg_utils as monoreg
from shutil import copyfile

framework_path_override = ''

if os.name == 'nt':
msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
if not msbuild_tools_path:
raise RuntimeError('Cannot find MSBuild Tools Path in the registry')
msbuild_path = os.path.join(msbuild_tools_path, 'MSBuild.exe')
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 = 'msbuild'
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)

output_path = os.path.abspath(os.path.join(str(target[0]), os.pardir))
build_config = 'Release'

msbuild_args = [
msbuild_path,
os.path.abspath(str(source[0])),
'/p:Configuration=Release',
'/p:OutputPath=' + output_path
'/p:Configuration=' + build_config,
]

if framework_path_override:
msbuild_args += ['/p:FrameworkPathOverride=' + framework_path_override]

msbuild_env = os.environ.copy()

# Needed when running from Developer Command Prompt for VS
if 'PLATFORM' in msbuild_env:
del msbuild_env['PLATFORM']

msbuild_alt_paths = [ 'xbuild' ]

while True:
try:
subprocess.check_call(msbuild_args, env = msbuild_env)
break
except subprocess.CalledProcessError:
raise RuntimeError('GodotSharpTools build failed')
except OSError:
if os.name != 'nt':
if not msbuild_alt_paths:
raise RuntimeError('Could not find commands msbuild or xbuild')
# Try xbuild
msbuild_args[0] = msbuild_alt_paths.pop(0)
else:
raise RuntimeError('Could not find command MSBuild.exe')
try:
subprocess.check_call(msbuild_args, env=msbuild_env)
except subprocess.CalledProcessError:
raise RuntimeError('GodotSharpTools build failed')

src_dir = os.path.abspath(os.path.join(str(source[0]), os.pardir, 'bin', build_config))
dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))

if not os.path.isdir(dst_dir):
if os.path.exists(dst_dir):
raise RuntimeError('Target directory is a file')
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)
env.Append(BUILDERS = { 'MonoBuildSolution' : mono_sln_builder })
env.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder})
env.MonoBuildSolution(
os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'),
'editor/GodotSharpTools/GodotSharpTools.sln'
Expand Down
80 changes: 58 additions & 22 deletions modules/mono/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import imp
import os
import sys
from shutil import copyfile

from SCons.Script import BoolVariable, Environment, Variables

Expand All @@ -16,8 +15,7 @@ def find_file_in_dir(directory, files, prefix='', extension=''):
for curfile in files:
if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
return curfile

return None
return ''


def can_build(platform):
Expand All @@ -31,13 +29,31 @@ def is_enabled():
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):
env.use_ptrcall = True

envvars = Variables()
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
envvars.Update(env)

bits = env['bits']

mono_static = env['mono_static']

mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
Expand All @@ -46,18 +62,18 @@ def configure(env):
if mono_static:
raise RuntimeError('mono-static: Not supported on Windows')

if env['bits'] == '32':
if bits == '32':
if os.getenv('MONO32_PREFIX'):
mono_root = os.getenv('MONO32_PREFIX')
elif os.name == 'nt':
mono_root = monoreg.find_mono_root_dir()
mono_root = monoreg.find_mono_root_dir(bits)
else:
if os.getenv('MONO64_PREFIX'):
mono_root = os.getenv('MONO64_PREFIX')
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')

mono_lib_path = os.path.join(mono_root, 'lib')
Expand All @@ -67,7 +83,7 @@ def configure(env):

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)

if os.getenv('VCINSTALLDIR'):
Expand All @@ -79,36 +95,31 @@ def configure(env):

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')
mono_dll_dst = os.path.join('bin', mono_dll_name + '.dll')
copy_mono_dll = True

if not os.path.isdir('bin'):
os.mkdir('bin')
elif os.path.exists(mono_dll_dst):
copy_mono_dll = False
if not mono_dll_name:
raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)

if copy_mono_dll:
copyfile(mono_dll_src, mono_dll_dst)
copy_file_no_replace(mono_bin_path, 'bin', mono_dll_name + '.dll')
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'):
mono_root = os.getenv('MONO32_PREFIX')
else:
if 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')

env.Append(LIBPATH=mono_lib_path)
env.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))

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)

env.Append(CPPFLAGS=['-D_REENTRANT'])
Expand All @@ -130,12 +141,37 @@ def configure(env):
elif sys.platform == "linux" or sys.platform == "linux2":
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:
if mono_static:
raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')

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')


Expand Down
Loading

0 comments on commit 09a1e11

Please sign in to comment.