From ad7597415fd391aaeba52b1d341c9193cb0bcaa6 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Tue, 15 Nov 2016 18:24:16 +0800 Subject: [PATCH] Visual Studio builds: Add support scripts to generate .pc files --- build/win32/Makefile.am | 3 + build/win32/gtkpc.py | 81 ++++++++++++++++++++++++++ build/win32/pc_base.py | 124 ++++++++++++++++++++++++++++++++++++++++ build/win32/replace.py | 109 +++++++++++++++++++++++++++++++++++ 4 files changed, 317 insertions(+) create mode 100644 build/win32/gtkpc.py create mode 100644 build/win32/pc_base.py create mode 100644 build/win32/replace.py diff --git a/build/win32/Makefile.am b/build/win32/Makefile.am index 9a28fa3c60..3ad51d8833 100644 --- a/build/win32/Makefile.am +++ b/build/win32/Makefile.am @@ -36,4 +36,7 @@ EXTRA_DIST += \ detectenv-msvc.mak \ introspection-msvc.mak \ gtk-introspection-msvc.mak \ + gtkpc.py \ + pc_base.py \ + replace.py \ $(GENERATED_ITEMS) diff --git a/build/win32/gtkpc.py b/build/win32/gtkpc.py new file mode 100644 index 0000000000..f13321459d --- /dev/null +++ b/build/win32/gtkpc.py @@ -0,0 +1,81 @@ +#!/usr/bin/python +# +# Utility script to generate .pc files for GTK+ +# for Visual Studio builds, to be used for +# building introspection files + +# Author: Fan, Chun-wei +# Date: April 26, 2016 + +import os +import sys +import argparse + +from replace import replace_multi, replace +from pc_base import BasePCItems + +def main(argv): + base_pc = BasePCItems() + + gdk_parser = argparse.ArgumentParser(description='Setup basic .pc file info') + gdk_parser.add_argument('--host', + required=True, + help='Build type') + base_pc.setup(argv, gdk_parser) + + atk_min_ver = '1.29.2' + cairo_min_ver = '1.6' + gdk_pixbuf_min_ver = '2.21.0' + gdk_win32_sys_libs = '-lgdi32 -limm32 -lshell32 -lole32 -lwinmm' + glib_min_ver = '2.28.0' + + cairo_backends = 'cairo-win32' + gdktarget = 'win32' + gio_package = 'gio-2.0 >= ' + glib_min_ver + + gdk_args = gdk_parser.parse_args() + + pkg_replace_items = {'@GTK_API_VERSION@': '2.0', + '@gdktarget@': gdktarget} + + pkg_required_packages = 'gdk-pixbuf-2.0 >= ' + gdk_pixbuf_min_ver + ' ' + \ + 'cairo >= ' + cairo_min_ver + ' ' + + gdk_pc_replace_items = {'@GDK_PACKAGES@': gio_package + ' ' + \ + 'pangowin32 pangocairo' + ' ' + \ + pkg_required_packages, + '@GDK_PRIVATE_PACKAGES@': gio_package + ' ' + cairo_backends, + '@GDK_EXTRA_LIBS@': gdk_win32_sys_libs, + '@GDK_EXTRA_CFLAGS@': ''} + + gtk_pc_replace_items = {'@host@': gdk_args.host, + '@GTK_BINARY_VERSION@': '2.10.0', + '@GTK_PACKAGES@': 'atk >= ' + atk_min_ver + ' ' + \ + pkg_required_packages + ' ' + \ + gio_package, + '@GTK_PRIVATE_PACKAGES@': 'atk', + '@GTK_EXTRA_CFLAGS@': '', + '@GTK_EXTRA_LIBS@': '', + '@GTK_EXTRA_CFLAGS@': ''} + + pkg_replace_items.update(base_pc.base_replace_items) + gdk_pc_replace_items.update(pkg_replace_items) + gtk_pc_replace_items.update(pkg_replace_items) + + # Generate gdk-2.0.pc + replace_multi(base_pc.top_srcdir + '/gdk-2.0.pc.in', + base_pc.srcdir + '/gdk-2.0.pc', + gdk_pc_replace_items) + + # Generate gtk+-2.0.pc + replace_multi(base_pc.top_srcdir + '/gtk+-2.0.pc.in', + base_pc.srcdir + '/gtk+-2.0.pc', + gtk_pc_replace_items) + + # Generate gail.pc + replace_multi(base_pc.top_srcdir + '/gail.pc.in', + base_pc.srcdir + '/gail.pc', + pkg_replace_items) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/build/win32/pc_base.py b/build/win32/pc_base.py new file mode 100644 index 0000000000..587ba83d19 --- /dev/null +++ b/build/win32/pc_base.py @@ -0,0 +1,124 @@ +#!/usr/bin/python +# +# Simple utility script to generate the basic info +# needed in a .pc (pkg-config) file, used especially +# for introspection purposes + +# This can be used in various projects where +# there is the need to generate .pc files, +# and is copied from GLib's $(srcroot)/build/win32 + +# Author: Fan, Chun-wei +# Date: March 10, 2016 + +import os +import sys +import argparse + +class BasePCItems: + def __init__(self): + self.base_replace_items = {} + self.exec_prefix = '' + self.includedir = '' + self.libdir = '' + self.prefix = '' + self.srcdir = os.path.dirname(__file__) + self.top_srcdir = self.srcdir + '\\..\\..' + self.version = '' + + def setup(self, argv, parser=None): + if parser is None: + parser = argparse.ArgumentParser(description='Setup basic .pc file info') + parser.add_argument('--prefix', help='prefix of the installed library', + required=True) + parser.add_argument('--exec-prefix', + help='prefix of the installed programs, \ + if different from the prefix') + parser.add_argument('--includedir', + help='includedir of the installed library, \ + if different from ${prefix}/include') + parser.add_argument('--libdir', + help='libdir of the installed library, \ + if different from ${prefix}/lib') + parser.add_argument('--version', help='Version of the package', + required=True) + args = parser.parse_args() + + self.version = args.version + + # check whether the prefix and exec_prefix are valid + if not os.path.exists(args.prefix): + raise SystemExit('Specified prefix \'%s\' is invalid' % args.prefix) + + # use absolute paths for prefix + self.prefix = os.path.abspath(args.prefix).replace('\\','/') + + # check and setup the exec_prefix + if getattr(args, 'exec_prefix', None) is None: + exec_prefix_use_shorthand = True + self.exec_prefix = '${prefix}' + else: + if args.exec_prefix.startswith('${prefix}'): + exec_prefix_use_shorthand = True + input_exec_prefix = args.prefix + args.exec_prefix[len('${prefix}'):] + else: + exec_prefix_use_shorthand = False + input_exec_prefix = args.exec_prefix + if not os.path.exists(input_exec_prefix): + raise SystemExit('Specified exec_prefix \'%s\' is invalid' % + args.exec_prefix) + if exec_prefix_use_shorthand is True: + self.exec_prefix = args.exec_prefix.replace('\\','/') + else: + self.exec_prefix = os.path.abspath(input_exec_prefix).replace('\\','/') + + # check and setup the includedir + if getattr(args, 'includedir', None) is None: + self.includedir = '${prefix}/include' + else: + if args.includedir.startswith('${prefix}'): + includedir_use_shorthand = True + input_includedir = args.prefix + args.includedir[len('${prefix}'):] + else: + if args.includedir.startswith('${exec_prefix}'): + includedir_use_shorthand = True + input_includedir = input_exec_prefix + args.includedir[len('${exec_prefix}'):] + else: + includedir_use_shorthand = False + input_includedir = args.includedir + if not os.path.exists(input_includedir): + raise SystemExit('Specified includedir \'%s\' is invalid' % + args.includedir) + if includedir_use_shorthand is True: + self.includedir = args.includedir.replace('\\','/') + else: + self.includedir = os.path.abspath(input_includedir).replace('\\','/') + + # check and setup the libdir + if getattr(args, 'libdir', None) is None: + self.libdir = '${prefix}/lib' + else: + if args.libdir.startswith('${prefix}'): + libdir_use_shorthand = True + input_libdir = args.prefix + args.libdir[len('${prefix}'):] + else: + if args.libdir.startswith('${exec_prefix}'): + libdir_use_shorthand = True + input_libdir = input_exec_prefix + args.libdir[len('${exec_prefix}'):] + else: + libdir_use_shorthand = False + input_libdir = args.libdir + if not os.path.exists(input_libdir): + raise SystemExit('Specified libdir \'%s\' is invalid' % + args.libdir) + if libdir_use_shorthand is True: + self.libdir = args.libdir.replace('\\','/') + else: + self.libdir = os.path.abspath(input_libdir).replace('\\','/') + + # setup dictionary for replacing items in *.pc.in + self.base_replace_items.update({'@VERSION@': self.version}) + self.base_replace_items.update({'@prefix@': self.prefix}) + self.base_replace_items.update({'@exec_prefix@': self.exec_prefix}) + self.base_replace_items.update({'@libdir@': self.libdir}) + self.base_replace_items.update({'@includedir@': self.includedir}) diff --git a/build/win32/replace.py b/build/win32/replace.py new file mode 100644 index 0000000000..a81bab9426 --- /dev/null +++ b/build/win32/replace.py @@ -0,0 +1,109 @@ +#!/usr/bin/python +# +# Simple utility script to manipulate +# certain types of strings in a file + +# This can be used in various projects where +# there is the need to replace strings in files, +# and is copied from GLib's $(srcroot)/build/win32 + +# Author: Fan, Chun-wei +# Date: September 03, 2014 + +import os +import sys +import re +import string +import argparse + +valid_actions = ['remove-prefix', + 'replace-var', + 'replace-str', + 'remove-str'] + +def replace_multi(src, dest, replace_items): + with open(src, 'r') as s: + with open(dest, 'w') as d: + for line in s: + replace_dict = dict((re.escape(key), value) \ + for key, value in replace_items.items()) + replace_pattern = re.compile("|".join(replace_dict.keys())) + d.write(replace_pattern.sub(lambda m: \ + replace_dict[re.escape(m.group(0))], line)) + +def replace(src, dest, instring, outstring): + replace_item = {instring: outstring} + replace_multi(src, dest, replace_item) + +def check_required_args(args, params): + for param in params: + if getattr(args, param, None) is None: + raise SystemExit('%s: error: --%s argument is required' % (__file__, param)) + +def warn_ignored_args(args, params): + for param in params: + if getattr(args, param, None) is not None: + print('%s: warning: --%s argument is ignored' % (__file__, param)) + +def main(argv): + + parser = argparse.ArgumentParser(description='Process strings in a file.') + parser.add_argument('-a', + '--action', + help='Action to carry out. Can be one of:\n' + 'remove-prefix\n' + 'replace-var\n' + 'replace-str\n' + 'remove-str', + choices=valid_actions) + parser.add_argument('-i', '--input', help='Input file') + parser.add_argument('-o', '--output', help='Output file') + parser.add_argument('--instring', help='String to replace or remove') + parser.add_argument('--var', help='Autotools variable name to replace') + parser.add_argument('--outstring', + help='New String to replace specified string or variable') + parser.add_argument('--removeprefix', help='Prefix of string to remove') + + args = parser.parse_args() + + input_string = '' + output_string = '' + + # We must have action, input, output for all operations + check_required_args(args, ['action','input','output']) + + # Build the arguments by the operation that is to be done, + # to be fed into replace() + + # Get rid of prefixes from a string + if args.action == 'remove-prefix': + check_required_args(args, ['instring','removeprefix']) + warn_ignored_args(args, ['outstring','var']) + input_string = args.removeprefix + args.instring + output_string = args.instring + + # Replace an m4-style variable (those surrounded by @...@) + if args.action == 'replace-var': + check_required_args(args, ['var','outstring']) + warn_ignored_args(args, ['instring','removeprefix']) + input_string = '@' + args.var + '@' + output_string = args.outstring + + # Replace a string + if args.action == 'replace-str': + check_required_args(args, ['instring','outstring']) + warn_ignored_args(args, ['var','removeprefix']) + input_string = args.instring + output_string = args.outstring + + # Remove a string + if args.action == 'remove-str': + check_required_args(args, ['instring']) + warn_ignored_args(args, ['var','outstring','removeprefix']) + input_string = args.instring + output_string = '' + + replace(args.input, args.output, input_string, output_string) + +if __name__ == '__main__': + sys.exit(main(sys.argv))