1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
#!/usr/bin/env python3
import re
from collections import defaultdict
from pathlib import Path
def get_program_parameters():
import argparse
description = 'Generate a find_package(VTK COMPONENTS ...) that lists all modules referenced by a set of files.'
epilogue = '''
This uses the VTK source folder to determine the modules and headers.
Then the user files/folders are looked at to find the headers being used.
Finally a find_package() is output with the modules you need for
inclusion in your CMakeLists.txt file.
Note:
1) If include file(s) are not found when building your application.
You may need to search the VTK source to find where the file is.
Then look at contents of vtk.module in that folder and add the
module name to the find_package statement.
2) If linking fails, it usually means that the needed module has not been
built, so you may need to add it to your VTK build and rebuild VTK.
3) More modules than strictly necessary may be included.
'''
parser = argparse.ArgumentParser(description=description, epilog=epilogue,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('vtk_path', help='The path to the VTK source tree.')
parser.add_argument('application', nargs='+', help='Paths to the application files or folders.')
args = parser.parse_args()
return args.vtk_path, args.application
def check_paths(vtk_src_dir, application_srcs):
"""
Check that the paths are valid.
:param vtk_src_dir: The path to the VTK source.
:param application_srcs: The user source files to be scanned for modules.
:return: True if paths, files exist.
"""
ok = True
if not Path(vtk_src_dir).is_dir():
print('The path to your VTK Source folder does not exist.')
print(Path(vtk_src_dir))
ok = False
bad_paths = list()
for f in application_srcs:
p = Path(f)
if not (p.is_dir() or p.is_file()):
bad_paths.append(p)
if bad_paths:
print('These application paths or files do not exist.')
for p in bad_paths:
print(p)
ok = False
return ok
def find_vtk_modules(vtk_src_dir):
"""
Build a dict of the VTK Module name, library name(if it exists) and any header files.
:param vtk_src_dir: The path to the VTK source folder
:return: Module name, library name and headers.
"""
vtk_modules = defaultdict(dict)
modules = [f for f in Path(vtk_src_dir).rglob('vtk.module')]
# Includes in the module path
file_patterns = ['vtk*.h', 'vtk*.h.in', 'QVTK*.h', '*QtQuick.h']
for module in modules:
content = module.read_text()
args = content.split('\n')
# Assuming NAME is always there.
if 'NAME' in args:
name = args[args.index('NAME') + 1].strip()
if 'LIBRARY_NAME' in args:
library_name = args[args.index('LIBRARY_NAME') + 1].strip()
else:
library_name = None
headers = list()
for pattern in file_patterns:
if pattern == 'vtk*.h.in':
# These files will be converted to header files in the build folder of VTK.
headers.extend([f.with_suffix('').name for f in module.parent.glob(pattern)])
else:
headers.extend([f.name for f in module.parent.glob(pattern)])
vtk_modules[name]['library_name'] = library_name
vtk_modules[name]['headers'] = headers
return vtk_modules
def build_headers_modules(modules):
"""
Make a dictionary whose key is the header filename and value is the module.
:param modules: The modules.
:return: Headers and their corresponding module.
"""
# The headers should be unique to a module, however we will not assume this.
headers_modules = defaultdict(set)
for k, v in modules.items():
if 'headers' in v:
for k1 in v['headers']:
headers_modules[k1].add(k)
return headers_modules
def find_application_includes(path):
"""
Build a set that contains the vtk includes found in the file.
:param path: The path to the application file.
:return: The includes that were found.
"""
includes = set()
include_hdr1 = re.compile(r'((?:vtk|QVTK).*\.h)')
include_hdr2 = re.compile(r'(\w+QtQuick\.h)')
content = path.read_text()
incs = include_hdr1.findall(content)
includes.update(incs)
incs = include_hdr2.findall(content)
includes.update(incs)
return includes
def generate_find_package(vtk_src_dir, application_srcs):
"""
Generate the find_package statement.
:param vtk_src_dir: The VTK source folder.
:param application_srcs: A list of application folders and or files.
:return: The find_package statement.
"""
vtk_modules = find_vtk_modules(vtk_src_dir)
# Test to see if VTK source is provided
if len(vtk_modules) == 0:
print(vtk_src_dir, 'is not a VTK source directory. It does not contain any vtk.module files.')
return None
vtk_headers_modules = build_headers_modules(vtk_modules)
valid_extensions = ['.h', '.hxx', '.txx', '.cpp', '.cxx', '.cc']
# Build a set of includes for all command line files
all_includes = set()
for app_src in application_srcs:
p = Path(app_src)
if p.is_file():
if p.suffix in valid_extensions:
all_includes.update(find_application_includes(p))
elif p.is_dir():
paths = list()
for ext in valid_extensions:
paths.extend([f for f in p.rglob('*' + ext) if f.is_file()])
for path in paths:
all_includes.update(find_application_includes(path))
if len(all_includes) == 0:
print('No VTK includes found in the application files.')
return None
# Build a set that contains all modules referenced in the user files.
all_modules = set()
for inc in all_includes:
if inc in vtk_headers_modules:
for m in vtk_headers_modules[inc]:
all_modules.add(m)
if 'VTK::RenderingCore' in all_modules:
all_modules.add('VTK::RenderingOpenGL2')
all_modules.add('VTK::InteractionStyle')
all_modules.add('VTK::RenderingFreeType')
all_modules.add('VTK::RenderingGL2PSOpenGL2')
all_modules.add('VTK::RenderingContextOpenGL2')
if 'VTK::DomainsChemistry' in all_modules:
all_modules.add('VTK::DomainsChemistryOpenGL2')
if 'VTK::RenderingVolume' in all_modules:
all_modules.add('VTK::RenderingVolumeOpenGL2')
if 'VTK::RenderingContext2D' in all_modules:
all_modules.add('VTK::RenderingContextOpenGL2')
if 'VTK::IOExport' in all_modules:
all_modules.add('VTK::RenderingContextOpenGL2')
all_modules.add('VTK::IOExportOpenGL2')
all_modules.add('VTK::IOExportPDF')
all_modules.add('VTK::RenderingContextOpenGL2')
res = ['All modules referenced in your files:', 'find_package(VTK', ' COMPONENTS']
for m in sorted(all_modules):
res.append(' ' * 2 + m.replace('VTK::', ''))
res.append(')')
res.append(
'Your application code includes ' + str(len(all_modules)) + ' of ' + str(
len(vtk_modules)) + ' vtk modules.')
return res
def main():
vtk_src_dir, application_srcs = get_program_parameters()
if not check_paths(vtk_src_dir, application_srcs):
return
res = generate_find_package(vtk_src_dir, application_srcs)
if res:
print('\n'.join(res))
if __name__ == '__main__':
print('If you have built VTK and\n modules.json is available in the build folder.')
print(' Please consider using FindNeededModules.py instead.')
main()
|