From 3ee62d301f476444147a6a9ff6d478803eb85a8b Mon Sep 17 00:00:00 2001 From: Fabien LOISON Date: Mon, 24 Oct 2022 12:57:02 +0200 Subject: [PATCH 1/4] Update winbuild tools and Gtk (gvsbuild, Nuitka,...) --- winbuild/build-gtk.bat | 12 +- winbuild/build-yoga.bat | 1 + winbuild/patch/cygwinccompiler.py | 415 ------------------------------ winbuild/requirements.txt | 2 +- winbuild/yoga-image-optimizer.py | 9 - 5 files changed, 6 insertions(+), 433 deletions(-) delete mode 100644 winbuild/patch/cygwinccompiler.py diff --git a/winbuild/build-gtk.bat b/winbuild/build-gtk.bat index 68a1805..9bd44bc 100644 --- a/winbuild/build-gtk.bat +++ b/winbuild/build-gtk.bat @@ -1,4 +1,4 @@ -SET GVSBUILD_REV=9b10978a8c5aa539f4280feeaa69bc5cc8bf9fbf +SET GVSBUILD_REV=2022.4.1 SET ROOTDIR=%CD% :: Get or update gvsbuild @@ -14,20 +14,16 @@ IF NOT EXIST build\gvsbuild ( git checkout %GVSBUILD_REV% ) -:: Install the Python version that will be used to build... +:: Install the Python version that will be used to build python build.py build ^ -p x64 ^ - --vs-ver 16 ^ + --vs-ver 17 ^ python -:: ... and patch it to allow our build to work -COPY %ROOTDIR%\winbuild\patch\cygwinccompiler.py ^ - C:\gtk-build\tools\python.3.9.2\tools\lib\distutils\cygwinccompiler.py - :: build Gtk with introspection enabled and Adwaita python build.py build ^ -p x64 ^ - --vs-ver 16 ^ + --vs-ver 17 ^ --enable-gi ^ gtk3 adwaita-icon-theme diff --git a/winbuild/build-yoga.bat b/winbuild/build-yoga.bat index 926ead0..a720893 100644 --- a/winbuild/build-yoga.bat +++ b/winbuild/build-yoga.bat @@ -37,6 +37,7 @@ python -m nuitka ^ --include-package=PIL ^ --include-package-data=yoga_image_optimizer ^ --plugin-enable=multiprocessing ^ + --plugin-enable=gi ^ --windows-disable-console ^ --windows-icon-from-ico=winbuild\icon.ico ^ --standalone ^ diff --git a/winbuild/patch/cygwinccompiler.py b/winbuild/patch/cygwinccompiler.py deleted file mode 100644 index 01d7292..0000000 --- a/winbuild/patch/cygwinccompiler.py +++ /dev/null @@ -1,415 +0,0 @@ -"""distutils.cygwinccompiler - -Provides the CygwinCCompiler class, a subclass of UnixCCompiler that -handles the Cygwin port of the GNU C compiler to Windows. It also contains -the Mingw32CCompiler class which handles the mingw32 port of GCC (same as -cygwin in no-cygwin mode). -""" - -# problems: -# -# * if you use a msvc compiled python version (1.5.2) -# 1. you have to insert a __GNUC__ section in its config.h -# 2. you have to generate an import library for its dll -# - create a def-file for python??.dll -# - create an import library using -# dlltool --dllname python15.dll --def python15.def \ -# --output-lib libpython15.a -# -# see also http://starship.python.net/crew/kernr/mingw32/Notes.html -# -# * We put export_symbols in a def-file, and don't use -# --export-all-symbols because it doesn't worked reliable in some -# tested configurations. And because other windows compilers also -# need their symbols specified this no serious problem. -# -# tested configurations: -# -# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works -# (after patching python's config.h and for C++ some other include files) -# see also http://starship.python.net/crew/kernr/mingw32/Notes.html -# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works -# (ld doesn't support -shared, so we use dllwrap) -# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now -# - its dllwrap doesn't work, there is a bug in binutils 2.10.90 -# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html -# - using gcc -mdll instead dllwrap doesn't work without -static because -# it tries to link against dlls instead their import libraries. (If -# it finds the dll first.) -# By specifying -static we force ld to link against the import libraries, -# this is windows standard and there are normally not the necessary symbols -# in the dlls. -# *** only the version of June 2000 shows these problems -# * cygwin gcc 3.2/ld 2.13.90 works -# (ld supports -shared) -# * mingw gcc 3.2/ld 2.13 works -# (ld supports -shared) - -import os -import sys -import copy -from subprocess import Popen, PIPE, check_output -import re - -from distutils.unixccompiler import UnixCCompiler -from distutils.file_util import write_file -from distutils.errors import (DistutilsExecError, CCompilerError, - CompileError, UnknownFileError) -from distutils.version import LooseVersion -from distutils.spawn import find_executable - -def get_msvcr(): - """Include the appropriate MSVC runtime library if Python was built - with MSVC 7.0 or later. - """ - msc_pos = sys.version.find('MSC v.') - if msc_pos != -1: - msc_ver = sys.version[msc_pos+6:msc_pos+10] - if msc_ver == '1300': - # MSVC 7.0 - return ['msvcr70'] - elif msc_ver == '1310': - # MSVC 7.1 - return ['msvcr71'] - elif msc_ver == '1400': - # VS2005 / MSVC 8.0 - return ['msvcr80'] - elif msc_ver == '1500': - # VS2008 / MSVC 9.0 - return ['msvcr90'] - elif msc_ver == '1600': - # VS2010 / MSVC 10.0 - return ['msvcr100'] - elif msc_ver == '1700': - # Visual Studio 2012 / Visual C++ 11.0 - return ['msvcr110'] - elif msc_ver == '1800': - # Visual Studio 2013 / Visual C++ 12.0 - return ['msvcr120'] - elif msc_ver == '1900': - # Visual Studio 2015 / Visual C++ 14.0 - return ['vcruntime140'] - elif msc_ver == '1928': - # Visual Studio 2015 / Visual C++ 14.2 - return ['vcruntime142'] - else: - raise ValueError("Unknown MS Compiler version %s " % msc_ver) - - -class CygwinCCompiler(UnixCCompiler): - """ Handles the Cygwin port of the GNU C compiler to Windows. - """ - compiler_type = 'cygwin' - obj_extension = ".o" - static_lib_extension = ".a" - shared_lib_extension = ".dll" - static_lib_format = "lib%s%s" - shared_lib_format = "%s%s" - exe_extension = ".exe" - - def __init__(self, verbose=0, dry_run=0, force=0): - - UnixCCompiler.__init__(self, verbose, dry_run, force) - - status, details = check_config_h() - self.debug_print("Python's GCC status: %s (details: %s)" % - (status, details)) - if status is not CONFIG_H_OK: - self.warn( - "Python's pyconfig.h doesn't seem to support your compiler. " - "Reason: %s. " - "Compiling may fail because of undefined preprocessor macros." - % details) - - self.gcc_version, self.ld_version, self.dllwrap_version = \ - get_versions() - self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % - (self.gcc_version, - self.ld_version, - self.dllwrap_version) ) - - # ld_version >= "2.10.90" and < "2.13" should also be able to use - # gcc -mdll instead of dllwrap - # Older dllwraps had own version numbers, newer ones use the - # same as the rest of binutils ( also ld ) - # dllwrap 2.10.90 is buggy - if self.ld_version >= "2.10.90": - self.linker_dll = "gcc" - else: - self.linker_dll = "dllwrap" - - # ld_version >= "2.13" support -shared so use it instead of - # -mdll -static - if self.ld_version >= "2.13": - shared_option = "-shared" - else: - shared_option = "-mdll -static" - - # Hard-code GCC because that's what this is all about. - # XXX optimization, warnings etc. should be customizable. - self.set_executables(compiler='gcc -mcygwin -O -Wall', - compiler_so='gcc -mcygwin -mdll -O -Wall', - compiler_cxx='g++ -mcygwin -O -Wall', - linker_exe='gcc -mcygwin', - linker_so=('%s -mcygwin %s' % - (self.linker_dll, shared_option))) - - # cygwin and mingw32 need different sets of libraries - if self.gcc_version == "2.91.57": - # cygwin shouldn't need msvcrt, but without the dlls will crash - # (gcc version 2.91.57) -- perhaps something about initialization - self.dll_libraries=["msvcrt"] - self.warn( - "Consider upgrading to a newer version of gcc") - else: - # Include the appropriate MSVC runtime library if Python was built - # with MSVC 7.0 or later. - self.dll_libraries = get_msvcr() - - def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): - """Compiles the source by spawning GCC and windres if needed.""" - if ext == '.rc' or ext == '.res': - # gcc needs '.res' and '.rc' compiled to object files !!! - try: - self.spawn(["windres", "-i", src, "-o", obj]) - except DistutilsExecError as msg: - raise CompileError(msg) - else: # for other files use the C-compiler - try: - self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + - extra_postargs) - except DistutilsExecError as msg: - raise CompileError(msg) - - def link(self, target_desc, objects, output_filename, output_dir=None, - libraries=None, library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): - """Link the objects.""" - # use separate copies, so we can modify the lists - extra_preargs = copy.copy(extra_preargs or []) - libraries = copy.copy(libraries or []) - objects = copy.copy(objects or []) - - # Additional libraries - libraries.extend(self.dll_libraries) - - # handle export symbols by creating a def-file - # with executables this only works with gcc/ld as linker - if ((export_symbols is not None) and - (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): - # (The linker doesn't do anything if output is up-to-date. - # So it would probably better to check if we really need this, - # but for this we had to insert some unchanged parts of - # UnixCCompiler, and this is not what we want.) - - # we want to put some files in the same directory as the - # object files are, build_temp doesn't help much - # where are the object files - temp_dir = os.path.dirname(objects[0]) - # name of dll to give the helper files the same base name - (dll_name, dll_extension) = os.path.splitext( - os.path.basename(output_filename)) - - # generate the filenames for these files - def_file = os.path.join(temp_dir, dll_name + ".def") - lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a") - - # Generate .def file - contents = [ - "LIBRARY %s" % os.path.basename(output_filename), - "EXPORTS"] - for sym in export_symbols: - contents.append(sym) - self.execute(write_file, (def_file, contents), - "writing %s" % def_file) - - # next add options for def-file and to creating import libraries - - # dllwrap uses different options than gcc/ld - if self.linker_dll == "dllwrap": - extra_preargs.extend(["--output-lib", lib_file]) - # for dllwrap we have to use a special option - extra_preargs.extend(["--def", def_file]) - # we use gcc/ld here and can be sure ld is >= 2.9.10 - else: - # doesn't work: bfd_close build\...\libfoo.a: Invalid operation - #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) - # for gcc/ld the def-file is specified as any object files - objects.append(def_file) - - #end: if ((export_symbols is not None) and - # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): - - # who wants symbols and a many times larger output file - # should explicitly switch the debug mode on - # otherwise we let dllwrap/ld strip the output file - # (On my machine: 10KiB < stripped_file < ??100KiB - # unstripped_file = stripped_file + XXX KiB - # ( XXX=254 for a typical python extension)) - if not debug: - extra_preargs.append("-s") - - UnixCCompiler.link(self, target_desc, objects, output_filename, - output_dir, libraries, library_dirs, - runtime_library_dirs, - None, # export_symbols, we do this in our def-file - debug, extra_preargs, extra_postargs, build_temp, - target_lang) - - # -- Miscellaneous methods ----------------------------------------- - - def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): - """Adds supports for rc and res files.""" - if output_dir is None: - output_dir = '' - obj_names = [] - for src_name in source_filenames: - # use normcase to make sure '.rc' is really '.rc' and not '.RC' - base, ext = os.path.splitext(os.path.normcase(src_name)) - if ext not in (self.src_extensions + ['.rc','.res']): - raise UnknownFileError("unknown file type '%s' (from '%s')" % \ - (ext, src_name)) - if strip_dir: - base = os.path.basename (base) - if ext in ('.res', '.rc'): - # these need to be compiled to object files - obj_names.append (os.path.join(output_dir, - base + ext + self.obj_extension)) - else: - obj_names.append (os.path.join(output_dir, - base + self.obj_extension)) - return obj_names - -# the same as cygwin plus some additional parameters -class Mingw32CCompiler(CygwinCCompiler): - """ Handles the Mingw32 port of the GNU C compiler to Windows. - """ - compiler_type = 'mingw32' - - def __init__(self, verbose=0, dry_run=0, force=0): - - CygwinCCompiler.__init__ (self, verbose, dry_run, force) - - # ld_version >= "2.13" support -shared so use it instead of - # -mdll -static - if self.ld_version >= "2.13": - shared_option = "-shared" - else: - shared_option = "-mdll -static" - - # A real mingw32 doesn't need to specify a different entry point, - # but cygwin 2.91.57 in no-cygwin-mode needs it. - if self.gcc_version <= "2.91.57": - entry_point = '--entry _DllMain@12' - else: - entry_point = '' - - if is_cygwingcc(): - raise CCompilerError( - 'Cygwin gcc cannot be used with --compiler=mingw32') - - self.set_executables(compiler='gcc -O -Wall', - compiler_so='gcc -mdll -O -Wall', - compiler_cxx='g++ -O -Wall', - linker_exe='gcc', - linker_so='%s %s %s' - % (self.linker_dll, shared_option, - entry_point)) - # Maybe we should also append -mthreads, but then the finished - # dlls need another dll (mingwm10.dll see Mingw32 docs) - # (-mthreads: Support thread-safe exception handling on `Mingw32') - - # no additional libraries needed - self.dll_libraries=[] - - # Include the appropriate MSVC runtime library if Python was built - # with MSVC 7.0 or later. - self.dll_libraries = get_msvcr() - -# Because these compilers aren't configured in Python's pyconfig.h file by -# default, we should at least warn the user if he is using an unmodified -# version. - -CONFIG_H_OK = "ok" -CONFIG_H_NOTOK = "not ok" -CONFIG_H_UNCERTAIN = "uncertain" - -def check_config_h(): - """Check if the current Python installation appears amenable to building - extensions with GCC. - - Returns a tuple (status, details), where 'status' is one of the following - constants: - - - CONFIG_H_OK: all is well, go ahead and compile - - CONFIG_H_NOTOK: doesn't look good - - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h - - 'details' is a human-readable string explaining the situation. - - Note there are two ways to conclude "OK": either 'sys.version' contains - the string "GCC" (implying that this Python was built with GCC), or the - installed "pyconfig.h" contains the string "__GNUC__". - """ - - # XXX since this function also checks sys.version, it's not strictly a - # "pyconfig.h" check -- should probably be renamed... - - from distutils import sysconfig - - # if sys.version contains GCC then python was compiled with GCC, and the - # pyconfig.h file should be OK - if "GCC" in sys.version: - return CONFIG_H_OK, "sys.version mentions 'GCC'" - - # let's see if __GNUC__ is mentioned in python.h - fn = sysconfig.get_config_h_filename() - try: - config_h = open(fn) - try: - if "__GNUC__" in config_h.read(): - return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn - else: - return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn - finally: - config_h.close() - except OSError as exc: - return (CONFIG_H_UNCERTAIN, - "couldn't read '%s': %s" % (fn, exc.strerror)) - -RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)') - -def _find_exe_version(cmd): - """Find the version of an executable by running `cmd` in the shell. - - If the command is not found, or the output does not match - `RE_VERSION`, returns None. - """ - executable = cmd.split()[0] - if find_executable(executable) is None: - return None - out = Popen(cmd, shell=True, stdout=PIPE).stdout - try: - out_string = out.read() - finally: - out.close() - result = RE_VERSION.search(out_string) - if result is None: - return None - # LooseVersion works with strings - # so we need to decode our bytes - return LooseVersion(result.group(1).decode()) - -def get_versions(): - """ Try to find out the versions of gcc, ld and dllwrap. - - If not possible it returns None for it. - """ - commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version'] - return tuple([_find_exe_version(cmd) for cmd in commands]) - -def is_cygwingcc(): - '''Try to determine if the gcc that would be used is from cygwin.''' - out_string = check_output(['gcc', '-dumpmachine']) - return out_string.strip().endswith(b'cygwin') diff --git a/winbuild/requirements.txt b/winbuild/requirements.txt index 5f2d174..3c6b678 100644 --- a/winbuild/requirements.txt +++ b/winbuild/requirements.txt @@ -1,3 +1,3 @@ nox==2020.12.31 -nuitka==0.6.13 +nuitka@https://github.com/flozz/Nuitka/archive/refs/heads/v1.1.6-patched-gi.zip wheel==0.36.2 diff --git a/winbuild/yoga-image-optimizer.py b/winbuild/yoga-image-optimizer.py index 9669384..96804f0 100755 --- a/winbuild/yoga-image-optimizer.py +++ b/winbuild/yoga-image-optimizer.py @@ -12,15 +12,6 @@ os.environ["GI_TYPELIB_PATH"] = str(ROOT / "gtk" / "lib" / "girepository-1.0") os.environ["XDG_DATA_DIRS"] = str(ROOT / "gtk" / "share") -import gi.overrides.Gtk # noqa: F401, E402 -import gi.overrides.GLib # noqa: F401, E402 -import gi.overrides.GObject # noqa: F401, E402 - -# From gi.overrides.Gdk (importing it do not work...) -from gi.repository import Gdk # noqa: E402 - -Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS") - if __name__ == "__main__": from yoga_image_optimizer.__main__ import main From 4bff0db91eafdf62a7912ea63cb6c3a1ce392fd8 Mon Sep 17 00:00:00 2001 From: Fabien LOISON Date: Mon, 24 Oct 2022 13:40:45 +0200 Subject: [PATCH 2/4] Update winbuild setup instructions --- winbuild/README.rst | 29 ++++++++++++++++++++++++----- winbuild/windows-readme.dist.txt | 7 ++++--- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/winbuild/README.rst b/winbuild/README.rst index 439fe65..d1a06fc 100644 --- a/winbuild/README.rst +++ b/winbuild/README.rst @@ -7,29 +7,48 @@ Requirements To build YOGA Image Optimizer for Windows, you must first install the following dependencies: -* Python 3.9: +* Windows 11: + + * Download (VM): https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/ + +Install Chocolatey (optional, but simpler setup): + + * Run in PowerShell as administrator: + ``Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))`` + * NOTE: all ``choco`` commands should be run as administrator + +* Python 3.10: * 64bit version * Must be added to the PATH (there is a checkbox during the installation) * Virtualenv must be installed and available in the PATH too * Download: https://www.python.org/ + * Choco: ``choco install python`` + +* Git: + + * Download: https://git-scm.com/ + * Choco: ``choco install git`` * MSYS2: * Install it at default location (``C:\msys64``) * Download: https://www.msys2.org/ + * Choco: ``choco install msys2`` -* Git: - - * Download: https://git-scm.com/ +* Visual Studio 17 (2022) -* Visual Studio 16 (2019) + * Already installed in the Windows 11 Dev VM, else use Chocolatey + * Choco: ``choco install visualstudio2022-workload-vctools`` * Inno Setup * Install it at default location (``C:\Program Files (x86)\Inno Setup 6\\``) or change its path in ``build-installer.bat`` * Download: https://jrsoftware.org/isinfo.php + * Choco: ``choco install innosetup`` + +Restart to finish setup. Building YOGA Image Optimizer for Windows diff --git a/winbuild/windows-readme.dist.txt b/winbuild/windows-readme.dist.txt index 92fe713..9bd2e77 100644 --- a/winbuild/windows-readme.dist.txt +++ b/winbuild/windows-readme.dist.txt @@ -11,7 +11,8 @@ Usage Just double-click on "yoga-image-optimizer.exe" to start the software. -Project's page --------------- +Project's pages +--------------- -https://github.com/flozz/yoga-image-optimizer +* https://yoga.flozz.org/ +* https://github.com/flozz/yoga-image-optimizer From f33c630a434e5c297f7cc45cf804b705a2bc4f2b Mon Sep 17 00:00:00 2001 From: Fabien LOISON Date: Mon, 24 Oct 2022 18:56:12 +0200 Subject: [PATCH 3/4] Fix a syntax error in the winbuild README --- winbuild/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winbuild/README.rst b/winbuild/README.rst index d1a06fc..822fcb0 100644 --- a/winbuild/README.rst +++ b/winbuild/README.rst @@ -11,7 +11,7 @@ dependencies: * Download (VM): https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/ -Install Chocolatey (optional, but simpler setup): +* Install Chocolatey (optional, but simpler setup): * Run in PowerShell as administrator: ``Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))`` From 8872e0d110b056a407d757d7debcbd373ef808cc Mon Sep 17 00:00:00 2001 From: Fabien LOISON Date: Tue, 22 Nov 2022 13:33:18 +0100 Subject: [PATCH 4/4] Update Nuitka to latest version --- winbuild/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winbuild/requirements.txt b/winbuild/requirements.txt index 3c6b678..244b97a 100644 --- a/winbuild/requirements.txt +++ b/winbuild/requirements.txt @@ -1,3 +1,3 @@ nox==2020.12.31 -nuitka@https://github.com/flozz/Nuitka/archive/refs/heads/v1.1.6-patched-gi.zip +nuitka==1.2.2 wheel==0.36.2