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 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
#!/usr/bin/env python3
import difflib
import os
import shlex
import subprocess
import sys
import tempfile
CMAKELISTS = """
cmake_minimum_required(VERSION 3.8)
project(find_paraview C CXX)
find_package(ParaView REQUIRED COMPONENTS %(components)s)
set(vtk_components %(vtk_components)s)
if (vtk_components)
find_package(VTK REQUIRED COMPONENTS ${vtk_components})
endif ()
set(src "${CMAKE_CURRENT_BINARY_DIR}/src.cxx")
file(WRITE "${src}" "
int main(int argc, char* argv[]) {
(void)argc;
(void)argv;
return 0;
}
")
add_executable(with_paraview "${src}")
target_compile_definitions(with_paraview
PRIVATE
WITH_PARAVIEW)
target_link_libraries(with_paraview
PRIVATE
${ParaView_LIBRARIES}
${VTK_LIBRARIES}
-LWITH_PARAVIEW)
# Explicitly not doing autoinit since the generated header gets deleted.
#vtk_module_autoinit(
# TARGETS with_paraview
# MODULES ${ParaView_LIBRARIES})
add_executable(without_paraview "${src}")
target_compile_definitions(without_paraview
PRIVATE
WITHOUT_PARAVIEW)
target_link_libraries(without_paraview
PRIVATE
-LWITHOUT_PARAVIEW)
"""
def diff_commands(a, b):
a_args = shlex.split(a)
b_args = shlex.split(b)
a_flags = []
b_flags = []
differ = difflib.SequenceMatcher(a=a_args, b=b_args, autojunk=False)
for tag, i1, i2, j1, j2 in differ.get_opcodes():
if tag in ('delete', 'replace'):
a_flags.extend(a_args[i1:i2])
if tag in ('insert', 'replace'):
b_flags.extend(b_args[j1:j2])
return (a_flags, b_flags)
def test_diff_commands():
cmd_a = 'prog -lcommon a_different common'
cmd_b = 'prog -lcommon b_different common'
(a_flags, b_flags) = diff_commands(cmd_a, cmd_b)
assert a_flags == ['a_different']
assert b_flags == ['b_different']
def extract_flags(compile_with, compile_without, link_with, link_without):
(_, compile_flags) = diff_commands(compile_without, compile_with)
(_, link_flags) = diff_commands(link_without, link_with)
# Remove our marker flags.
compile_flags.remove('-DWITH_PARAVIEW')
link_flags.remove('-LWITH_PARAVIEW')
# Remove target-specific flags.
def is_target_specific(arg):
return arg.find('with_paraview') > -1
compile_flags = [
flag for flag in compile_flags if not is_target_specific(flag)]
link_flags = [flag for flag in link_flags if not is_target_specific(flag)]
return (compile_flags, link_flags)
def test_extract_flags():
cmd_without_compile = \
'compiler -DWITHOUT_PARAVIEW -o without_paraview.dir/src.cxx.o src.cxx'
cmd_without_link = \
'compiler -LWITHOUT_PARAVIEW with_paraview.dir/src.cxx.o'
cmd_with_compile = \
'compiler -DWITH_PARAVIEW -I/path/to/paraview/includes -o with_paraview.dir/src.cxx.o src.cxx'
cmd_with_link = \
'compiler -LWITH_PARAVIEW /path/to/pv.so with_paraview.dir/src.cxx.o'
(compile_flags, link_flags) = \
extract_flags(cmd_with_compile, cmd_without_compile, cmd_with_link,
cmd_without_link)
assert compile_flags == ['-I/path/to/paraview/includes']
assert link_flags == ['/path/to/pv.so']
def extract_paraview_flags(components, cmake='cmake',
prefix=None,
verbose=False,
generator='Unix Makefiles',
paraview_dir=None, vtk_components=[]):
cmake_format = {}
cmake_format['components'] = ' '.join(components)
cmake_format['vtk_components'] = ' '.join(vtk_components)
def tempdir():
if sys.version_info.major == 3:
return tempfile.TemporaryDirectory()
else:
class DummyTemporaryDirectory:
def __init__(self):
self._dir = tempfile.mkdtemp()
def __enter__(self):
return self._dir
def __exit__(self, *args):
import shutil
shutil.rmtree(self._dir)
return DummyTemporaryDirectory()
with tempdir() as workdir:
srcdir = os.path.join(workdir, 'src')
builddir = os.path.join(workdir, 'build')
os.mkdir(srcdir)
os.mkdir(builddir)
# Write the CMake file.
with open(os.path.join(srcdir, 'CMakeLists.txt'), 'w+') as fout:
fout.write(CMAKELISTS % cmake_format)
# Configure the build tree.
configure_cmd = [
cmake,
'-G' + generator,
srcdir,
]
if prefix is not None:
configure_cmd.append('-DCMAKE_PREFIX_PATH:STRING=' + prefix)
if paraview_dir is not None:
paraview_dir = os.path.abspath(paraview_dir)
configure_cmd.append('-DParaView_DIR:PATH=' + paraview_dir)
if sys.version_info.major == 3:
stdout = subprocess.DEVNULL
else:
stdout = open('/dev/null', 'w')
subprocess.check_call(configure_cmd, cwd=builddir,
stdout=stdout)
if sys.version_info.major == 2:
stdout.close()
# Run the build tool.
build_cmd = [
cmake,
'--build', '.',
'--',
]
build_env = os.environ.copy()
if generator == 'Ninja':
build_cmd.append('-n')
build_cmd.append('-v')
build_env['NINJA_STATUS'] = ''
elif generator == 'Unix Makefiles':
# This doesn't work because the link line is actually behind
# another rule.
# build_cmd.append('-n')
build_cmd.append('VERBOSE=1')
else:
raise RuntimeError('Unsupported generator %s' % generator)
build_output = subprocess.Popen(build_cmd,
cwd=builddir,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=build_env)
lines = {}
lines['compile_with'] = None
lines['link_with'] = None
lines['compile_without'] = None
lines['link_without'] = None
def check_line(lines, line, flag, key):
if lines[key] is None and line.find(flag) > -1:
lines[key] = line
for line in build_output.stdout:
line = line.strip().decode('utf-8')
if verbose:
print(line)
check_line(lines, line, '-DWITH_PARAVIEW', 'compile_with')
check_line(lines, line, '-LWITH_PARAVIEW', 'link_with')
check_line(lines, line, '-DWITHOUT_PARAVIEW', 'compile_without')
check_line(lines, line, '-LWITHOUT_PARAVIEW', 'link_without')
if not all(lines.values()):
raise RuntimeError('missing some compile line outputs')
return extract_flags(**lines)
if __name__ == '__main__':
if sys.version_info.major == 2:
sys.stderr.write('Warning: paraview-config supports Python2, but it is recommended to use Python3\n')
bindir = '@CMAKE_INSTALL_BINDIR@'
prefix = os.path.abspath(__file__)
for _ in os.path.split(bindir):
prefix = os.path.dirname(prefix)
import argparse
parser = argparse.ArgumentParser(
description='Extract required flags for linking to ParaView')
parser.add_argument(
'-c', '--component', metavar='COMPONENT', action='append',
default=[], dest='components',
help='Component to search for')
parser.add_argument(
'-v', '--vtk-component', metavar='COMPONENT', action='append',
default=[], dest='vtk_components',
help='VTK component to search for')
parser.add_argument(
'-C', '--cmake', metavar='CMAKE', default='cmake',
dest='cmake',
help='Path to CMake to use')
parser.add_argument(
'-G', '--generator', metavar='GENERATOR', default='Unix Makefiles',
choices=('Unix Makefiles', 'Ninja'), dest='generator',
help='The CMake generator to use')
parser.add_argument(
'-p', '--paraview', metavar='PARAVIEW DIR', default=None,
dest='paraview_dir',
help='Where to find paraview-config.cmake')
parser.add_argument(
'-f', '--cppflags', action='store_true', default=False,
dest='cppflags',
help='Print CPP flags for using the components')
parser.add_argument(
'-l', '--ldflags', action='store_true', default=False,
dest='ldflags',
help='Print linker flags for using the components')
parser.add_argument(
'-V', '--verbose', action='store_true', default=False,
dest='verbose',
help='Print all output')
opts = parser.parse_args()
(compile_flags, link_flags) = \
extract_paraview_flags(opts.components, cmake=opts.cmake,
generator=opts.generator,
prefix=prefix,
verbose=opts.verbose,
paraview_dir=opts.paraview_dir,
vtk_components=opts.vtk_components)
if opts.cppflags:
print(' '.join(compile_flags))
if opts.ldflags:
print(' '.join(link_flags))
|