From b61df29fc04648608c728d760ac00225fb84c890 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 14 Sep 2022 17:14:22 -0700
Subject: [PATCH v13 13/20] meson: WIP: Add some of the windows resource files

---
 src/bin/initdb/meson.build        |  6 ++
 src/bin/pg_dump/meson.build       | 18 ++++++
 src/bin/pg_test_fsync/meson.build |  5 ++
 src/bin/pgevent/meson.build       |  4 ++
 src/bin/psql/meson.build          |  6 ++
 src/interfaces/libpq/meson.build  |  5 ++
 contrib/pageinspect/meson.build   |  5 ++
 contrib/pg_walinspect/meson.build |  5 ++
 meson.build                       | 61 +++++++++++++++++++
 src/tools/rcgen                   | 99 +++++++++++++++++++++++++++++++
 10 files changed, 214 insertions(+)
 create mode 100755 src/tools/rcgen

diff --git a/src/bin/initdb/meson.build b/src/bin/initdb/meson.build
index 9f213274d2f..6ced9a31b80 100644
--- a/src/bin/initdb/meson.build
+++ b/src/bin/initdb/meson.build
@@ -7,6 +7,12 @@ initdb_sources += timezone_localtime_source
 
 #fixme: reimplement libpq_pgport logic
 
+if host_system == 'windows'
+  initdb_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'initdb',
+    '--FILEDESC', 'initdb - initialize a new database cluster',])
+endif
+
 initdb = executable('initdb',
   initdb_sources,
   include_directories: [timezone_inc],
diff --git a/src/bin/pg_dump/meson.build b/src/bin/pg_dump/meson.build
index 785ec094dbd..3527a25c288 100644
--- a/src/bin/pg_dump/meson.build
+++ b/src/bin/pg_dump/meson.build
@@ -24,6 +24,12 @@ pg_dump_sources = files(
   'pg_dump_sort.c',
 )
 
+if host_system == 'windows'
+  pg_dump_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pg_dump',
+    '--FILEDESC', 'pg_dump - backup one PostgreSQL database',])
+endif
+
 pg_dump = executable('pg_dump',
   pg_dump_sources,
   link_with: [pg_dump_common],
@@ -37,6 +43,12 @@ pg_dumpall_sources = files(
   'pg_dumpall.c',
 )
 
+if host_system == 'windows'
+  pg_dumpall_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pg_dumpall',
+    '--FILEDESC', 'pg_dumpall - backup PostgreSQL databases'])
+endif
+
 pg_dumpall = executable('pg_dumpall',
   pg_dumpall_sources,
   link_with: [pg_dump_common],
@@ -50,6 +62,12 @@ pg_restore_sources = files(
   'pg_restore.c',
 )
 
+if host_system == 'windows'
+  pg_restore_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pg_restore',
+    '--FILEDESC', 'pg_restore - restore PostgreSQL databases'])
+endif
+
 pg_restore = executable('pg_restore',
   pg_restore_sources,
   link_with: [pg_dump_common],
diff --git a/src/bin/pg_test_fsync/meson.build b/src/bin/pg_test_fsync/meson.build
index 2c01831e11f..2bbc3cb915d 100644
--- a/src/bin/pg_test_fsync/meson.build
+++ b/src/bin/pg_test_fsync/meson.build
@@ -1,5 +1,10 @@
 test_fsync_sources = files('pg_test_fsync.c')
 
+if host_system == 'windows'
+  test_fsync_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pg_test_fsync'])
+endif
+
 pg_test_fsync = executable('pg_test_fsync',
   test_fsync_sources,
   dependencies: [frontend_code],
diff --git a/src/bin/pgevent/meson.build b/src/bin/pgevent/meson.build
index 5852bca4d87..2e9aea4b0e1 100644
--- a/src/bin/pgevent/meson.build
+++ b/src/bin/pgevent/meson.build
@@ -6,6 +6,10 @@ pgevent_sources = files(
   'pgevent.c',
 )
 
+pgevent_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+  '--NAME', 'pgevent',
+  '--FILEDESC', 'Eventlog message formatter',])
+
 pgevent_sources += windows.compile_resources('pgmsgevent.rc')
 
 # FIXME: copied from Mkvcbuild.pm, but I don't think that's the right approach
diff --git a/src/bin/psql/meson.build b/src/bin/psql/meson.build
index ea850c8fdf5..3474389d3b6 100644
--- a/src/bin/psql/meson.build
+++ b/src/bin/psql/meson.build
@@ -38,6 +38,12 @@ generated_sources += sql_help.to_list()
 psql_sources += sql_help
 bin_targets += sql_help
 
+if host_system == 'windows'
+  psql_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'psql',
+    '--FILEDESC', 'psql - the PostgreSQL interactive terminal',])
+endif
+
 psql = executable('psql',
   psql_sources,
   include_directories: include_directories('.'),
diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build
index bc047e00d62..2c9edeaa088 100644
--- a/src/interfaces/libpq/meson.build
+++ b/src/interfaces/libpq/meson.build
@@ -16,9 +16,13 @@ libpq_sources = files(
   'libpq-events.c',
   'pqexpbuffer.c',
 )
+libpq_so_sources = [] # only for shared lib, in addition to above
 
 if host_system == 'windows'
   libpq_sources += files('pthread-win32.c', 'win32.c')
+  libpq_so_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'libpq',
+    '--FILEDESC', 'PostgreSQL Access Library',])
 endif
 
 if ssl.found()
@@ -52,6 +56,7 @@ libpq_st = static_library('libpq',
 # not using both_libraries here, causes problems with precompiled headers and
 # resource files with msbuild
 libpq_so = shared_library('libpq',
+  libpq_so_sources,
   dependencies: libpq_deps,
   include_directories: [libpq_inc, postgres_inc],
   c_args: ['-DSO_MAJOR_VERSION=5'],
diff --git a/contrib/pageinspect/meson.build b/contrib/pageinspect/meson.build
index 4af8153e4fd..050d60525c7 100644
--- a/contrib/pageinspect/meson.build
+++ b/contrib/pageinspect/meson.build
@@ -9,6 +9,11 @@ pageinspect_sources = files(
   'rawpage.c',
 )
 
+if host_system == 'windows'
+  initdb_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pageinspect',])
+endif
+
 pageinspect = shared_module('pageinspect',
   pageinspect_sources,
   kwargs: contrib_mod_args,
diff --git a/contrib/pg_walinspect/meson.build b/contrib/pg_walinspect/meson.build
index d6b27877dd0..aafd9a37f23 100644
--- a/contrib/pg_walinspect/meson.build
+++ b/contrib/pg_walinspect/meson.build
@@ -1,5 +1,10 @@
 pg_walinspect_sources = files('pg_walinspect.c')
 
+if host_system == 'windows'
+  pg_walinspect_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'pg_walinspect'])
+endif
+
 pg_walinspect = shared_module('pg_walinspect',
   pg_walinspect_sources,
   kwargs: contrib_mod_args + {
diff --git a/meson.build b/meson.build
index d5411831e82..11ce27c60ee 100644
--- a/meson.build
+++ b/meson.build
@@ -2525,6 +2525,67 @@ gen_export_kwargs = {
 
 
 
+###
+### windows resources related stuff
+###
+
+if host_system == 'windows'
+  pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
+  win32ver_rc = files('src/port/win32ver.rc')
+  rcgen = find_program('src/tools/rcgen', native: true)
+
+  rcgen_base_args = [
+    '--srcdir', '@SOURCE_DIR@',
+    '--builddir', meson.build_root(),
+    '--rcout', '@OUTPUT0@',
+    '--out', '@OUTPUT1@',
+    '--input', '@INPUT@',
+    '@EXTRA_ARGS@',
+  ]
+
+  if cc.get_argument_syntax() == 'msvc'
+    rcgen_base_args += [
+      '--rc', find_program('rc', required: true).path(),
+    ]
+    rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
+  else
+    rcgen_base_args += [
+      '--windres', find_program('windres', required: true).path(),
+    ]
+    rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
+  endif
+
+  # msbuild backend doesn't support this atm
+  if meson.backend() == 'ninja'
+    rcgen_base_args += ['--depfile', '@DEPFILE@']
+  endif
+
+  rcgen_bin_args = rcgen_base_args + [
+    '--VFT_TYPE', 'VFT_APP',
+    '--FILEENDING', 'exe',
+    '--ICO', pg_ico
+  ]
+
+  rcgen_lib_args = rcgen_base_args + [
+    '--VFT_TYPE', 'VFT_DLL',
+    '--FILEENDING', 'dll',
+  ]
+
+  rc_bin_gen = generator(rcgen,
+    depfile: '@BASENAME@.d',
+    arguments: rcgen_bin_args,
+    output: rcgen_outputs,
+  )
+
+  rc_lib_gen = generator(rcgen,
+    depfile: '@BASENAME@.d',
+    arguments: rcgen_lib_args,
+    output: rcgen_outputs,
+  )
+endif
+
+
+
 # headers that the whole build tree depends on
 generated_headers = []
 # headers that the backend build depends on
diff --git a/src/tools/rcgen b/src/tools/rcgen
new file mode 100755
index 00000000000..5b62bfe5410
--- /dev/null
+++ b/src/tools/rcgen
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import subprocess
+import sys
+
+parser = argparse.ArgumentParser(description='generate PostgreSQL rc file')
+
+parser.add_argument('--srcdir', type=os.path.abspath,
+                    required=True)
+parser.add_argument('--builddir', type=os.path.abspath,
+                    required=True)
+
+binaries = parser.add_argument_group('binaries')
+binaries.add_argument('--windres', type=os.path.abspath)
+binaries.add_argument('--rc', type=os.path.abspath)
+
+inout = parser.add_argument_group('inout')
+inout.add_argument('--depfile', type=argparse.FileType('w'))
+inout.add_argument('--input', type=argparse.FileType('r'),
+                   required=True)
+inout.add_argument('--rcout', type=argparse.FileType('w'),
+                   required=True)
+inout.add_argument('--out', type=str,
+                   required=True)
+
+replacements = parser.add_argument_group('replacements')
+replacements.add_argument('--FILEDESC', type=str)
+replacements.add_argument('--NAME', type=str, required=True)
+replacements.add_argument('--VFT_TYPE', type=str, required=True)
+replacements.add_argument('--FILEENDING', type=str, required=True)
+replacements.add_argument('--ICO', type=str)
+
+args = parser.parse_args()
+
+# determine replacement strings
+
+internal_name = '"{0}"'.format(args.NAME)
+original_name = '"{0}.{1}"'.format(args.NAME, args.FILEENDING)
+
+# if no description is passed in, generate one based on the name
+if args.FILEDESC:
+    filedesc = args.FILEDESC
+elif args.NAME:
+    if args.VFT_TYPE == 'VFT_DLL':
+        filedesc = 'PostgreSQL {0} library'.format(args.NAME)
+    else:
+        filedesc = 'PostgreSQL {0} binary'.format(args.NAME)
+filedesc = '"{0}"'.format(filedesc)
+
+
+if args.ICO:
+    ico = 'IDI_ICON ICON "{0}"'.format(args.ICO)
+    if args.depfile:
+        args.depfile.write("{0} : {1}\n".format(args.rcout.name, args.ICO))
+else:
+    ico = ''
+
+
+data = args.input.read()
+
+data = data.replace('VFT_APP', args.VFT_TYPE)
+data = data.replace('_INTERNAL_NAME_', internal_name)
+data = data.replace('_ORIGINAL_NAME_', original_name)
+data = data.replace('FILEDESC', filedesc)
+data = data.replace("_ICO_", ico)
+
+args.rcout.write(data)
+args.rcout.close()
+
+if args.windres:
+    cmd = [
+        args.windres,
+        '-I{0}/src/include/'.format(args.builddir),
+        '-I{0}/src/include/'.format(args.srcdir),
+        '-o', args.out, '-i', args.rcout.name,
+    ]
+elif args.rc:
+    cmd = [
+        args.rc, '/nologo',
+        '-I{0}/src/include/'.format(args.builddir),
+        '-I{0}/src/include/'.format(args.srcdir),
+        '/fo', args.out, args.rcout.name,
+    ]
+else:
+    sys.exit('either --windres or --rc needs to be specified')
+
+sp = subprocess.run(cmd)
+if sp.returncode != 0:
+    sys.exit(sp.returncode)
+
+# It'd be nicer if we could generate correct dependencies here, but 'rc'
+# doesn't support doing so. It's unlikely we'll ever need more, so...
+if args.depfile:
+    args.depfile.write("{0} : {1}\n".format(
+        args.rcout.name, args.input.name))
+    args.depfile.write("{0} : {1}/{2}\n".format(
+        args.out, args.builddir, 'src/include/pg_config.h'))
-- 
2.37.3.542.gdd3f6c4cae

