diff --git a/NuGet/Readme.md b/NuGet/Readme.md index a9764bdb9..3c34a23c0 100644 --- a/NuGet/Readme.md +++ b/NuGet/Readme.md @@ -25,7 +25,7 @@ pacman -S mingw-w64-x86_64-pango mingw-w64-x86_64-atk mingw-w64-x86_64-gtk3 And installed the executor python module ``` -C:\Python35\Scripts\pip.exe install executor +C:\Python35\Scripts\pip.exe install executor yattag vsgen ``` ### Running Build @@ -48,7 +48,7 @@ sudo apt-get install libglib2.0-dev libpango1.0-dev libatk1.0-dev libgtk-3-dev Then install the executor python module ``` -pip3 install executor +pip3 install executor yattag vsgen ``` The version of Nuget needs to be the latest for linux diff --git a/NuGet/build.py b/NuGet/build.py index 0fb9491b4..3ba9363bb 100644 --- a/NuGet/build.py +++ b/NuGet/build.py @@ -2,12 +2,14 @@ """Script to build out the .Net dll's and package them into a Nuget Package for gtksharp3""" import os, sys from pybuild.profiles.GtkSharp import GtkSharp +from pybuild.profiles.GtkSharp_Core import GtkSharp_Core from pybuild.profiles.Glue_Win32 import Glue_Win32 from pybuild.profiles.Glue_Win64 import Glue_Win64 from pybuild.profiles.Gtk_Win32 import Gtk_Win32 from pybuild.profiles.Gtk_Win64 import Gtk_Win64 -# Ideally I'd like to see the GtkSharp Build system redone via .Net Core or something other than make +# Ideally I'd like to see the GtkSharp Build system redone via the build system of .Net core (dotnet cli tool) +# and using Scons / Cuppa for the glue libraries # For now though we rely on the use of make to build the .Net dll's # under linux we run this natively, under windows we can use MSYS2 @@ -24,9 +26,8 @@ class Build(object): print ("Please use GtkSharp3_Build.py where is one of") print (" clean to clean the output directory: ./build") -# print (" gtksharp_all to build .Net libs for GtkSharp, via .Net 4.5 and .Net Core") - print (" gtksharp_net45 to build .Net libs for GtkSharp, via .Net 4.5") -# print (" gtksharp_core to build .Net libs for GtkSharp, via .Net Core") + print (" gtksharp to build .Net libs for GtkSharp, via .Net 4.5") + print (" gtksharp_core to build .Net libs for GtkSharp, via .Net 4.5 using the dotnet cli tool") print (" gtk_win32 to build the Nuget package for GtkSharp.Win32") print (" gtk_win64 to build the Nuget package for GtkSharp.Win64") @@ -38,7 +39,7 @@ class Build(object): return if sys.argv[1] == 'all': - self.runbuild('gtksharp_net45') + self.runbuild('gtksharp') self.runbuild('gtk_win32') self.runbuild('gtk_win64') return @@ -51,11 +52,18 @@ class Build(object): if build_type == 'clean': self.clean() - elif build_type == 'gtksharp_net45': + elif build_type == 'gtksharp': profile = GtkSharp() profile.clean() - profile.build_net45() - profile.copy_net45() + profile.build() + profile.copy() + profile.build_nuget() + + elif build_type == 'gtksharp_core': + profile = GtkSharp_Core() + profile.clean() + profile.build() + profile.copy_dll() profile.build_nuget() elif build_type == 'gtk_win32': diff --git a/NuGet/pybuild/profiles/Glue_Win32.py b/NuGet/pybuild/profiles/Glue_Win32.py index 0904563d9..5fa72f141 100644 --- a/NuGet/pybuild/profiles/Glue_Win32.py +++ b/NuGet/pybuild/profiles/Glue_Win32.py @@ -36,7 +36,7 @@ class Glue_Win32(ProfileBase): # Trigger build of gtksharp with specific bash for Mingw32 builder = GtkSharp() builder.MSYSTEM = self.MSYSTEM - builder.build_net45() + builder.build() net45_build_dir = join(self.Build_NugetDir, 'build', 'net45') os.makedirs(net45_build_dir, exist_ok=True) diff --git a/NuGet/pybuild/profiles/GtkSharp.py b/NuGet/pybuild/profiles/GtkSharp.py index b285658c0..f1a193e75 100644 --- a/NuGet/pybuild/profiles/GtkSharp.py +++ b/NuGet/pybuild/profiles/GtkSharp.py @@ -4,8 +4,6 @@ from pybuild.ProfileBase import ProfileBase from os.path import abspath, join from pybuild.Helper import Helper -# TODO Add .Net Core generation - class GtkSharp(ProfileBase): def __init__(self): @@ -19,7 +17,7 @@ class GtkSharp(ProfileBase): def Build_ScriptDir(self): return abspath(join(self._BuildDir, 'scripts')) - def build_net45(self): + def build(self): """Build the gtksharp binaries for .Net 4.5""" os.makedirs(self.Build_ScriptDir, exist_ok=True) buildfile = join(self.Build_ScriptDir, 'net45_build.sh') @@ -56,7 +54,7 @@ class GtkSharp(ProfileBase): cmd = Helper.run_cmd(cmds, self.SrcDir) - def copy_net45(self): + def copy(self): """Copy the .Net 4.5 dll's to the build dir""" net45_build_dir = join(self.Build_NugetDir, 'build', 'net45') diff --git a/NuGet/pybuild/profiles/GtkSharp_Core.py b/NuGet/pybuild/profiles/GtkSharp_Core.py new file mode 100644 index 000000000..078f376e1 --- /dev/null +++ b/NuGet/pybuild/profiles/GtkSharp_Core.py @@ -0,0 +1,155 @@ +#!/usr/bin/python3 +import os, shutil +from pybuild.ProfileBase import ProfileBase +from pybuild.vsgenext.CoreVSProject import CoreVSProject +from os.path import abspath, join +from pybuild.Helper import Helper +from glob import glob +import vsgen + +# Note at this stage we can't complile GtkSharp using the .Net Core platform libraries, such as netstandard1.6 +# https://docs.microsoft.com/en-us/dotnet/articles/standard/library +# This is due to some small api changes in the platform that the Gtksharp code would need to be adjusted to + +# We can however use the newer dotnet build system specifying the net461 platform +# This is the same set of platform libs under the surface (using mono) but a step in the right direction +# with modernising the build system. One advantage to this newer build system is that we don't need to list all the .cs files +# Within the project files (see generated .xproj file and project.json) + +# TODO look into package for symbols, via NuGet -symbols + +class GtkSharp_Core(ProfileBase): + + def __init__(self): + """Class Init""" + super().__init__() + self._NuGet_PackageName = 'GtkSharp.Core' + self._Version = Helper.get_gtksharp_version(self.SrcDir) + self.Solution = None + self.BuildConfig = 'Release' + + @property + def Build_CoreDir(self): + return abspath(join(self._BuildDir, 'core')) + + @property + def Dotnet_BuildExe(self): + return 'dotnet.exe' + + + def Copy_CS_Files(self, csfiles): + srclist = glob(join(self.SrcDir, csfiles[0])) + destdir = join(self.Build_CoreDir, csfiles[1]) + os.makedirs(destdir, exist_ok=True) + for fname in srclist: + shutil.copy(fname, destdir) + + def SetupProject(self, projname): + proj = CoreVSProject() + proj.Name = projname + proj.RootNamespace=projname + proj.FileName = join(self.Build_CoreDir, projname, projname + '.xproj') + proj.Frameworks = {'net461': {}} + proj.Depends = {} + proj.BuildOptions = { "allowUnsafe": True , "outputName": projname + "-sharp"} + proj.Version = self._Version + self.Solution.Projects.append(proj) + self.Solution.write() + return proj + + def Build_Project(self, proj): + projdir = join(self.Build_CoreDir, proj.Name) + Helper.run_cmd([self.Dotnet_BuildExe, 'restore'], projdir) + Helper.run_cmd([self.Dotnet_BuildExe, 'build', + '--configuration', self.BuildConfig, + '--framework', 'net461', + '--output', join(self.Build_CoreDir, 'build')] + , projdir) + + + def build(self): + """Build the gtksharp binaries for .Net 4.5""" + os.makedirs(self.Build_CoreDir, exist_ok=True) + self.Solution = vsgen.solution.VSGSolution() + self.Solution.FileName = join(self.Build_CoreDir, 'GtkSharp.sln') + + # Build Glib + self.Copy_CS_Files(['glib/*.cs', 'glib/']) + proj = self.SetupProject('glib') + proj.write() + self.Build_Project(proj) + + # Build Gio + self.Copy_CS_Files(['gio/*.cs', 'gio/']) + self.Copy_CS_Files(['gio/generated/GLib/*.cs', 'gio/generated/GLib/']) + proj = self.SetupProject('gio') + proj.Depends = {'glib': self._Version} + proj.write() + self.Build_Project(proj) + + # Build Cairo + self.Copy_CS_Files(['cairo/*.cs', 'cairo/']) + proj = self.SetupProject('cairo') + proj.write() + self.Build_Project(proj) + + # Build Pango + self.Copy_CS_Files(['pango/*.cs', 'pango/']) + self.Copy_CS_Files(['pango/generated/Pango/*.cs', 'pango/generated/Pango/']) + proj = self.SetupProject('pango') + proj.Depends = {'glib': self._Version, + 'cairo': self._Version} + proj.write() + self.Build_Project(proj) + + # Build Atk + self.Copy_CS_Files(['atk/*.cs', 'atk/']) + self.Copy_CS_Files(['atk/generated/Atk/*.cs', 'atk/generated/Atk/']) + proj = self.SetupProject('atk') + proj.Depends = {'glib': self._Version} + proj.write() + self.Build_Project(proj) + + # Build Gdk + self.Copy_CS_Files(['gdk/*.cs', 'gdk/']) + self.Copy_CS_Files(['gdk/generated/Gdk/*.cs', 'gdk/generated/Gdk/']) + self.Copy_CS_Files(['gdk/generated/GLib/*.cs', 'gdk/generated/GLib/']) + proj = self.SetupProject('gdk') + proj.Depends = {'atk': self._Version, + 'cairo': self._Version, + 'gio': self._Version, + 'glib': self._Version, + 'pango': self._Version} + proj.write() + self.Build_Project(proj) + + # Build Gtk + self.Copy_CS_Files(['gtk/*.cs', 'gtk/']) + self.Copy_CS_Files(['gtk/generated/GLib/*.cs', 'gtk/generated/GLib/']) + self.Copy_CS_Files(['gtk/generated/Gtk/*.cs', 'gtk/generated/Gtk/']) + proj = self.SetupProject('gtk') + proj.Depends = {'gdk': self._Version, + 'glib': self._Version} + proj.write() + self.Build_Project(proj) + + + def copy_dll(self): + """Copy the .Net 4.5 dll's to the build dir""" + + net45_build_dir = join(self.Build_NugetDir, 'build', 'net45') + net45_lib_dir = join(self.Build_NugetDir, 'lib', 'net45') + + os.makedirs(net45_build_dir, exist_ok=True) + os.makedirs(net45_lib_dir, exist_ok=True) + shutil.copy('./misc/GtkSharp.targets', net45_build_dir) + + srclist = glob(join(self.Build_CoreDir, 'build', '*.dll')) + for item in srclist: + shutil.copy(item, net45_lib_dir) + + # Get the Config files + dll_list = ['atk', 'cairo', 'gdk', 'gio', 'glib', 'gtk', 'pango'] + for item in dll_list: + if item != 'cairo': + shutil.copy(join(self.SrcDir, item, item + '-sharp.dll.config'), net45_build_dir) \ No newline at end of file diff --git a/NuGet/pybuild/vsgenext/CoreVSProject.py b/NuGet/pybuild/vsgenext/CoreVSProject.py new file mode 100644 index 000000000..520c0f763 --- /dev/null +++ b/NuGet/pybuild/vsgenext/CoreVSProject.py @@ -0,0 +1,144 @@ +#!/usr/bin/python3 + +import os, json +from vsgen.project import VSGProject +from xml.etree import ElementTree as et +from yattag import indent +from os.path import abspath, join +from collections import OrderedDict + +class CoreVSProject(VSGProject): + """ + CoreVSProject extends :class:`~vsgen.project.VSGProject` with data and logic needed to create a `.xproj` file. + :ivar str TargetFrameworkVersion: The target framework version. + :ivar str BaseIntermediateOutputPath: Intermediate path for building the output. + :ivar str ProjectXml: Override the xml within the .xproj file. + :ivar str ProjectJson: Override the json within the project.lock file. + """ + __project_type__ = 'netcore' + + __writable_name__ = "Visual Studio .Net Core Project" + + __registerable_name__ = "Visual Studio C# Compiler" + + def __init__(self, **kwargs): + """ + Constructor. + :param kwargs: List of arbitrary keyworded arguments to be processed as instance variable data + """ + super(CoreVSProject, self).__init__(**kwargs) + + def _import(self, datadict): + """ + Internal method to import instance variables data from a dictionary + :param dict datadict: The dictionary containing variables values. + """ + super(CoreVSProject, self)._import(datadict) + self.TargetFrameworkVersion = datadict.get('TargetFrameworkVersion', 'v4.6.1') + self.BaseIntermediateOutputPath = datadict.get('BaseIntermediateOutputPath', '.\obj') + self.ProjectXml = datadict.get('ProjectXml', None) + self.ProjectJson = datadict.get('ProjectJson', None) + self.Version = datadict.get('Version', '1.0.0-*') + self.Depends = datadict.get('Depends', {'NETStandard.Library': '1.6.0'}) + self.Frameworks = datadict.get('Frameworks', None) + self.BuildOptions = datadict.get('BuildOptions', None) + + def get_project_json(self): + """ + Get the json for use in Project.lock + """ + + data = OrderedDict() + ver = {'version': self.Version} + data.update(ver) + + depends = self.Depends + depends2 = {'dependencies': depends} + data.update(depends2) + + if self.Frameworks != None: + frameworks = {'frameworks': self.Frameworks} + else: + frameworks = {'frameworks': {'netstandard1.6': {'imports': 'dnxcore50'}}} + data.update(frameworks) + + if self.BuildOptions != None: + buildopts = {'buildOptions': self.BuildOptions} + data.update(buildopts) + + return data + + def get_project_xml(self): + """ + Get the xml for use in the xproj file + """ + + xml_projroot = et.Element('Project') + xml_projroot.set('ToolsVersion', '14.0') + xml_projroot.set('DefaultTargets', 'Build') + xml_projroot.set('xmlns', 'http://schemas.microsoft.com/developer/msbuild/2003') + + propgroup1 = et.SubElement(xml_projroot, 'PropertyGroup') + studiover = et.SubElement(propgroup1, 'VisualStudioVersion') + studiover.set('Condition', "'$(VisualStudioVersion)' == ''") + studiover.text = '14.0' + vstoolspath = et.SubElement(propgroup1, 'VSToolsPath') + vstoolspath.set('Condition', "'$(VSToolsPath)' == ''") + vstoolspath.text = r"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)" + + import1 = et.SubElement(xml_projroot, 'Import') + import1.set('Project', '$(VSToolsPath)\DotNet\Microsoft.DotNet.Props') + import1.set('Condition', "'$(VSToolsPath)' != ''") + + propgroup2 = et.SubElement(xml_projroot, 'PropertyGroup') + propgroup2.set('Label', 'Globals') + projguid = et.SubElement(propgroup2, 'ProjectGuid') + projguid.text = self.lower(self.GUID) + rootnamespace = et.SubElement(propgroup2, 'RootNamespace') + rootnamespace.text = self.RootNamespace + baseintermediateoutputpath = et.SubElement(propgroup2, 'BaseIntermediateOutputPath') + baseintermediateoutputpath.set('Condition', "'$(BaseIntermediateOutputPath)'=='' ") + baseintermediateoutputpath.text = self.BaseIntermediateOutputPath + targetframeworkversion = et.SubElement(propgroup2, 'TargetFrameworkVersion') + targetframeworkversion.text = self.TargetFrameworkVersion + + propgroup3 = et.SubElement(xml_projroot, 'PropertyGroup') + schemaver = et.SubElement(propgroup3, 'SchemaVersion') + schemaver.text = '2.0' + + import2 = et.SubElement(xml_projroot, 'Import') + import2.set('Project', '$(VSToolsPath)\DotNet\Microsoft.DotNet.targets') + import2.set('Condition', "'$(VSToolsPath)' != ''") + + etstr = et.tostring(xml_projroot, encoding='utf-8', method='xml').decode('utf-8') + outtxt = indent(etstr) + return outtxt + + + def write(self): + """ + Creates the project files. + """ + npath = os.path.normpath(self.FileName) + (filepath, filename) = os.path.split(npath) + os.makedirs(filepath, exist_ok=True) + + projectFileName = os.path.normpath(self.FileName) + projxml = '' + if self.ProjectXml == None: + projxml = self.get_project_xml() + else: + projxml = self.ProjectXml + with open(projectFileName, 'wt') as f: + f.write(projxml) + + jsonFileName = join(filepath, 'project.json') + + if self.ProjectJson == None: + projjson = self.get_project_json() + else: + projjson = self.ProjectJson + + with open(jsonFileName, 'w') as f: + txt = json.dumps(projjson, indent=2, separators=(',', ': ')) + f.write(txt) diff --git a/NuGet/pybuild/vsgenext/__init__.py b/NuGet/pybuild/vsgenext/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/NuGet/vs/GtkSharp-NugetBuild/GtkSharp-NugetBuild.pyproj b/NuGet/vs/GtkSharp-NugetBuild/GtkSharp-NugetBuild.pyproj index 1e2f66dec..6a9c1dcc7 100644 --- a/NuGet/vs/GtkSharp-NugetBuild/GtkSharp-NugetBuild.pyproj +++ b/NuGet/vs/GtkSharp-NugetBuild/GtkSharp-NugetBuild.pyproj @@ -7,7 +7,7 @@ ..\..\build.py - ..\..\;..\..\pybuild\ + ..\..\;..\..\pybuild\;..\..\pybuild\vsgen\ ..\..\ . GtkSharp-NugetBuild @@ -53,6 +53,9 @@ pybuild\profiles\GtkSharp.py + + pybuild\profiles\GtkSharp_Core.py + pybuild\profiles\Gtk_Win32.py @@ -62,12 +65,19 @@ pybuild\profiles\__init__.py + + pybuild\vsgenext\CoreVSProject.py + + + pybuild\vsgenext\__init__.py + pybuild\__init__.py +