1#!/usr/bin/env python3
2
3# External command, intended to be called with run_command(), custom_target(),
4# meson.add_install_script() and meson.add_dist_script().
5
6#                         argv[1]   argv[2:]
7# handle-built-files.py <subcommand> <xxx>...
8
9import os
10import sys
11import shutil
12import subprocess
13from pathlib import Path
14
15subcommand = sys.argv[1]
16
17# Invoked from custom_target() in meson.build.
18def build_from_m4():
19  #     argv[2]      argv[3]      argv[4]      argv[5]
20  # <include_dir> <input_file> <output_file> <stamp_file>
21
22  include_dir = sys.argv[2]
23  input_file = sys.argv[3]
24  output_file = sys.argv[4]
25  stamp_file = sys.argv[5]
26
27  # Create the destination directory, if it does not exist.
28  output_dir = os.path.dirname(output_file)
29  os.makedirs(output_dir, exist_ok=True)
30
31  cmd = [
32    'm4',
33    '-I', include_dir,
34    input_file,
35  ]
36  output_file_obj = open(output_file, mode='w')
37  result = subprocess.run(cmd, stdout=output_file_obj)
38  output_file_obj.close()
39
40  if result.returncode:
41    return result.returncode
42
43  if stamp_file.endswith('.cc'):
44    shutil.copy(output_file, stamp_file)
45  else:
46    Path(stamp_file).touch(exist_ok=True)
47  return 0
48
49# Invoked from meson.add_install_script().
50def install_built_h_files():
51  #    argv[2]       argv[3]          argv[4:]
52  # <built_h_dir> <install_subdir> <built_h_files>...
53
54  # <built_h_dir> is an absolute path in the build directory or source directory.
55  # <install_subdir> is an installation directory, relative to {prefix}.
56  built_h_dir = sys.argv[2]
57  install_dir_root = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), sys.argv[3])
58
59  for file in sys.argv[4:]:
60    path_h = os.path.join(built_h_dir, file)
61    rel_dir = os.path.dirname(file)
62    if rel_dir:
63      install_dir = os.path.join(install_dir_root, rel_dir)
64    else:
65      install_dir = install_dir_root
66    print('Installing ', path_h, ' to ', install_dir)
67
68    # Create the installation directory, if it does not exist.
69    os.makedirs(install_dir, exist_ok=True)
70
71    # shutil.copy2() copies timestamps and some other file metadata.
72    shutil.copy2(path_h, install_dir)
73  return 0
74
75# Invoked from meson.add_dist_script().
76def dist_built_files(is_msvc_files=False):
77  #     argv[2]        argv[3]     argv[4:]
78  # <built_h_cc_dir> <dist_dir> <built_files>...
79
80  # <built_h_cc_dir> is an absolute path in the build directory or source directory.
81  # <dist_dir> is a distribution directory, relative to MESON_DIST_ROOT.
82  built_h_cc_dir = sys.argv[2]
83  dist_dir_root = os.path.join(os.getenv('MESON_DIST_ROOT'), sys.argv[3])
84  dist_dir = dist_dir_root
85
86  # Distribute .h and .cc files built from .m4 files, or generated MSVC files.
87  for file in sys.argv[4:]:
88    if not is_msvc_files:
89      dist_dir = os.path.join(dist_dir_root, os.path.dirname(file))
90
91    # Create the distribution directory, if it does not exist.
92    os.makedirs(dist_dir, exist_ok=True)
93
94    shutil.copy(os.path.join(built_h_cc_dir, file), dist_dir)
95  return 0
96
97# Invoked from run_command() in meson.build.
98def copy_built_files():
99  #  argv[2]    argv[3]    argv[4:]
100  # <from_dir> <to_dir> <file_names>...
101
102  # <from_dir> is an absolute or relative path of the directory to copy from.
103  # <to_dir> is an absolute or relative path of the directory to copy to.
104  from_dir_root = sys.argv[2]
105  to_dir_root = sys.argv[3]
106
107  # Copy some built files if they exist in from_dir, but not in the destination
108  # directory, or if they are not up to date in the destination directory.
109  # (The term "source directory" is avoided here, because from_dir might not
110  # be what Meson calls a source directory as opposed to a build directory.)
111
112  # Copy .h and .cc files built from .m4 files.
113  for file in sys.argv[4:]:
114    from_file = os.path.join(from_dir_root, file)
115    to_file = os.path.join(to_dir_root, file)
116    if os.path.isfile(from_file) and ((not os.path.isfile(to_file))
117       or (os.stat(from_file).st_mtime > os.stat(to_file).st_mtime)):
118
119      # Create the destination directory, if it does not exist.
120      os.makedirs(os.path.dirname(to_file), exist_ok=True)
121
122      shutil.copy(from_file, to_file)
123  return 0
124
125# ----- Main -----
126if subcommand == 'build_from_m4':
127  sys.exit(build_from_m4())
128if subcommand == 'install_built_h_files':
129  sys.exit(install_built_h_files())
130if subcommand == 'dist_built_files':
131  sys.exit(dist_built_files())
132if subcommand == 'copy_built_files':
133  sys.exit(copy_built_files())
134if subcommand == 'dist_gen_msvc_files':
135  sys.exit(dist_built_files(True))
136print(sys.argv[0], ': illegal subcommand,', subcommand)
137sys.exit(1)
138