From be09b1f38d107789fc9ffe1cd2b2470552689a20 Mon Sep 17 00:00:00 2001
From: Diego Fronza <diego.fronza@percona.com>
Date: Mon, 10 Mar 2025 18:19:49 -0300
Subject: [PATCH] meson: Add LLVM bitcode emission for generated sources

This commit adds suport for bitcode emission for generated source files
(processed by bison, flex, etc).

Since generated sources are created with custom_target, we must handle
the source files differently when iterating over the list, as fs.parent
expects str or file object. The way to handle it is cast the object as
string `@0@.format(src)` then check if it's a custom target (a string
starting with `<CustomTarget`), if that's the case we can safely call
full_path() on it.

But we also want to generate bitcode files with path separators replaced
by underscore, relative to their source location, for that we strip
meson.build_root() from it.

Since generated backend sources may have their own compilation flags and
must also be included in the postgres.index.bc, the way to make it work
with current code was to create a new variable, called
`bc_generated_backend_sources`, which is a list of dictionaries, each
one having an optional 'additional_flags' and a `srclist` pointing to
the list of custom_target generated sources.

This list then has one dictionary entry for each generated backend
sources which share a separate compilation flag.

An example of a possible structure of bitcode_modules which is processed
by the main meson llvm bitcode emission file
src/backend/jit/llvm/bitcode/meson.build:
```
bitcode_modules = [
  {
    'name': 'postgres',
    'target': postgres_lib,
    'src_file': backend_sources,
    'gen_srcfiles': [
      {
        'additional_flags': [
          '-I/path/postgresl/src/backend/parser',
          '-I/path/postgresl/build/src/backend/parser',
        ],
        'srcfiles': [
                <custom_target for scan.c>,
                <custom_target for gram.c>
        ]
      }
    ]
  }
]
```
---
 contrib/cube/meson.build                 |  2 ++
 src/backend/jit/llvm/bitcode/meson.build | 37 ++++++++++++++++++++----
 src/backend/meson.build                  |  2 ++
 src/backend/parser/meson.build           |  8 +++++
 src/backend/utils/fmgr/meson.build       |  1 +
 5 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/contrib/cube/meson.build b/contrib/cube/meson.build
index 52bd6a9fb8..bbc03dd319 100644
--- a/contrib/cube/meson.build
+++ b/contrib/cube/meson.build
@@ -12,6 +12,7 @@ cube_scan = custom_target('cubescan',
 )
 generated_sources += cube_scan
 cube_sources += cube_scan
+bc_cube_sources += [cube_scan]
 
 cube_parse = custom_target('cubeparse',
   input: 'cubeparse.y',
@@ -19,6 +20,7 @@ cube_parse = custom_target('cubeparse',
 )
 generated_sources += cube_parse.to_list()
 cube_sources += cube_parse
+bc_cube_sources += cube_parse[0]
 
 if host_system == 'windows'
   cube_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
diff --git a/src/backend/jit/llvm/bitcode/meson.build b/src/backend/jit/llvm/bitcode/meson.build
index 577b4ddb21..acc13a1d16 100644
--- a/src/backend/jit/llvm/bitcode/meson.build
+++ b/src/backend/jit/llvm/bitcode/meson.build
@@ -9,18 +9,18 @@ foreach bitcode_module : bitcode_modules
   bitcode_obj = bitcode_module['target']
   bitcode_cflags_local = bitcode_cflags + bitcode_module.get('additional_flags', [])
 
-  if 'name' not in bitcode_module
-    bitcode_name = bitcode_obj.name()
-  else
-    bitcode_name = bitcode_module['name']
-  endif
+  bitcode_name = bitcode_module.get('name', bitcode_obj.name())
 
   foreach srcfile : bitcode_module['srcfiles']
-    if meson.version().version_compare('>=0.59')
+    srcfilename = '@0@'.format(srcfile)
+    if srcfilename.startswith('<CustomTarget')
+      srcfilename = srcfile.full_path().split(meson.build_root() + '/')[1]
+    elif meson.version().version_compare('>=0.59')
       srcfilename = fs.parent(srcfile) / fs.name(srcfile)
     else
       srcfilename = '@0@'.format(srcfile)
     endif
+
     targetname = '@0@_@1@.bc'.format(
       bitcode_name,
       srcfilename.underscorify(),
@@ -36,6 +36,31 @@ foreach bitcode_module : bitcode_modules
     )
   endforeach
 
+  # process generated sources, which may include custom compilation flags.
+  foreach gen_srcfiles: bitcode_module.get('gen_srcfiles', [])
+    bitcode_cflags_gen_local = bitcode_cflags_local + gen_srcfiles.get('additional_flags', [])
+
+    foreach srcfile: gen_srcfiles['srcfiles']
+      # generated sources are stored in some folder under meson.build_root()/**
+      # remove the build prefix from the string.
+      srcfilename = srcfile.full_path().split(meson.build_root() + '/')[1]
+
+      targetname = '@0@_@1@.bc'.format(
+        bitcode_name,
+        srcfilename.underscorify(),
+      )
+      bitcode_targets += custom_target(
+        targetname,
+        depends: [bitcode_module['target']],
+        input: [srcfile],
+        output: targetname,
+        command: [llvm_irgen_command, bitcode_cflags_gen_local],
+        install: true,
+        install_dir: dir_bitcode,
+      )
+    endforeach
+  endforeach
+
   index_name = '@0@.index.bc'.format(bitcode_name)
   bitcode_index = custom_target('@0@'.format(bitcode_name),
     output: index_name,
diff --git a/src/backend/meson.build b/src/backend/meson.build
index 5fb33660d3..76e5939fec 100644
--- a/src/backend/meson.build
+++ b/src/backend/meson.build
@@ -5,6 +5,7 @@ backend_sources = []
 backend_link_with = [pgport_srv, common_srv]
 
 generated_backend_sources = []
+bc_generated_backend_sources = []
 post_export_backend_sources = []
 
 subdir('access')
@@ -144,6 +145,7 @@ bitcode_modules += {
   'name': 'postgres',
   'target': postgres_lib,
   'srcfiles': backend_sources,
+  'gen_srcfiles': bc_generated_backend_sources,
 }
 
 pg_mod_c_args = cflags_mod
diff --git a/src/backend/parser/meson.build b/src/backend/parser/meson.build
index 874aa749aa..add472a0cd 100644
--- a/src/backend/parser/meson.build
+++ b/src/backend/parser/meson.build
@@ -42,6 +42,14 @@ backend_parser = custom_target('gram',
 generated_sources += backend_parser.to_list()
 parser_sources += backend_parser
 
+bc_generated_backend_sources += {
+  'additional_flags': [
+    '-I@0@'.format(meson.current_build_dir()),
+    '-I@0@'.format(meson.current_source_dir()),
+  ],
+  'srcfiles': [backend_scanner, backend_parser[0]],
+}
+
 parser = static_library('parser',
   parser_sources,
   dependencies: [backend_code],
diff --git a/src/backend/utils/fmgr/meson.build b/src/backend/utils/fmgr/meson.build
index b1dcab93e7..0119bc40cf 100644
--- a/src/backend/utils/fmgr/meson.build
+++ b/src/backend/utils/fmgr/meson.build
@@ -8,3 +8,4 @@ backend_sources += files(
 
 # fmgrtab.c
 generated_backend_sources += fmgrtab_target[2]
+bc_generated_backend_sources += {'srcfiles': [fmgrtab_target[2]]}
\ No newline at end of file
-- 
2.43.0

