Index: streamexecutor/CMakeLists.txt =================================================================== --- streamexecutor/CMakeLists.txt +++ streamexecutor/CMakeLists.txt @@ -2,6 +2,7 @@ option(STREAM_EXECUTOR_UNIT_TESTS "enable unit tests" ON) option(STREAM_EXECUTOR_ENABLE_DOXYGEN "enable StreamExecutor doxygen" ON) +option(STREAM_EXECUTOR_ENABLE_CONFIG_TOOL "enable building streamexecutor-config tool" ON) # First find includes relative to the streamexecutor top-level source path. include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include) @@ -64,6 +65,10 @@ add_subdirectory(lib) add_subdirectory(examples) +if(STREAM_EXECUTOR_ENABLE_CONFIG_TOOL ) + add_subdirectory(tools/streamexecutor-config) +endif(STREAM_EXECUTOR_ENABLE_CONFIG_TOOL ) + install(DIRECTORY include/ DESTINATION include) if (STREAM_EXECUTOR_ENABLE_DOXYGEN) Index: streamexecutor/Doxyfile.in =================================================================== --- streamexecutor/Doxyfile.in +++ streamexecutor/Doxyfile.in @@ -794,7 +794,7 @@ # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = */examples/* */unittests/* +EXCLUDE_PATTERNS = */examples/* */tools/* */unittests/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the Index: streamexecutor/tools/streamexecutor-config/CMakeLists.txt =================================================================== --- /dev/null +++ streamexecutor/tools/streamexecutor-config/CMakeLists.txt @@ -0,0 +1,3 @@ +find_package(PythonInterp REQUIRED) +configure_file(streamexecutor-config.in streamexecutor-config ESCAPE_QUOTES) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/streamexecutor-config DESTINATION bin) Index: streamexecutor/tools/streamexecutor-config/streamexecutor-config.in =================================================================== --- /dev/null +++ streamexecutor/tools/streamexecutor-config/streamexecutor-config.in @@ -0,0 +1,182 @@ +#!@PYTHON_EXECUTABLE@ +# +#===- streamexecutor-config - Build config script for SE -----*- python -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +r""" +Get configuration info needed to compile programs which use StreamExecutor. + +Runs llvm-config and adds StreamExecutor-specific flags to the output. Supports +only the subset of llvm-config flags that are relevant for applications +compiling against StreamExecutor. + +This utility will typically be used to construct a compile command line for an +application which depends on the StreamExecutor library. + +For example: + c++ example.cpp -o example \ + $(streamexecutor-config \ + --cppflags --cxxflags --ldflags --libs --system-libs) +""" + +import argparse +import errno +import os +import shlex +import subprocess +import sys + +def cuddle_flag(flag, tokens): + """If flag appears by itself in tokens, combines it with the next token. + + >>> tokens = ['-I', '/usr/include'] + >>> cuddle_flag('-I', tokens) + >>> tokens + ['-I/usr/include'] + + >>> tokens = ['-L', '/usr/lib'] + >>> cuddle_flag('-L', tokens) + >>> tokens + ['-L/usr/lib'] + + >>> tokens = ['-I'] + >>> cuddle_flag('-I', tokens) + >>> tokens + ['-I'] + + >>> tokens = ['-I', '/usr/include', '-I', '/usr/local/include'] + >>> cuddle_flag('-I', tokens) + >>> tokens + ['-I/usr/include', '-I/usr/local/include'] + """ + start = 0 + while True: + try: + index = tokens.index(flag, start) + except ValueError: + return + if index + 1 < len(tokens): + follower = tokens.pop(index + 1) + tokens[index] = flag + follower + start = index + 1 + +def get_llvm_config_output(flags_string): + """Calls llvm-config and returns the output with -I and -L flags cuddled.""" + output = subprocess.check_output( + ['llvm-config'] + flags_string.split()).strip() + tokens = shlex.split(output) + cuddle_flag('-I', tokens) + cuddle_flag('-L', tokens) + return ' '.join(tokens) + +def has_token(token, string): + """Checks if the given token appears in the string. + + The token argument must be a single shell token. + + >>> string = '-I/usr/include -L"/usr/lib"' + >>> has_token('-I/usr/include', string) + True + >>> has_token('-I/usr/local/include', string) + False + >>> has_token('-I"/usr/include"', string) + True + >>> has_token('-L"/usr/lib"', string) + True + >>> has_token('-L/usr/lib', string) + True + """ + split_token = shlex.split(token) + if len(split_token) > 1: + raise ValueError('has_token called with a multi-token token: ' + token) + escaped_token = split_token[0] + return escaped_token in shlex.split(string) + +def main(): + parser = argparse.ArgumentParser( + prog='streamexecutor-config', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=__doc__) + + parser.add_argument( + '--cppflags', + action='store_true', + help= + 'C preprocessor flags for files that include StreamExecutor headers.') + + parser.add_argument( + '--cxxflags', + action='store_true', + help='C++ compiler flags for files that include StreamExecutor headers.') + + parser.add_argument( + '--ldflags', + action='store_true', + help='Print linker flags.') + + parser.add_argument( + '--libs', + action='store_true', + help='Libraries needed to link against StreamExecutor.') + + parser.add_argument( + '--system-libs', + action='store_true', + help='System libraries needed to link against StreamExecutor.') + + # Print the help message if the user did not pass any arguments. + if len(sys.argv) <= 1: + parser.print_help() + sys.exit(1) + + args = parser.parse_args() + + # Check for the llvm-config executable in the path. + try: + with open(os.devnull, 'w') as devnull: + subprocess.call('llvm-config', stdout=devnull, stderr=devnull) + except OSError as err: + if err.errno != errno.ENOENT: + raise + sys.exit( + 'llvm-config not found in PATH, please add it to the PATH and retry') + + all_flags = [] + + if args.cppflags: + llvm_flags = get_llvm_config_output('--cppflags') + all_flags.append(llvm_flags) + se_flag = "-I'@CMAKE_INSTALL_PREFIX@/include'" + if not has_token(token=se_flag, string=llvm_flags): + all_flags.append(se_flag) + + if args.cxxflags: + all_flags.append(get_llvm_config_output('--cxxflags')) + + if args.ldflags: + llvm_flags = get_llvm_config_output('--ldflags') + all_flags.append(llvm_flags) + se_flag = "-L'@CMAKE_INSTALL_PREFIX@/lib'" + if not has_token(token=se_flag, string=llvm_flags): + all_flags.append(se_flag) + + if args.libs: + llvm_flags = get_llvm_config_output('--libs support symbolize') + se_flag = '-lstreamexecutor' + if not has_token(token=se_flag, string=llvm_flags): + all_flags.append(se_flag) + all_flags.append(llvm_flags) + + if args.system_libs: + all_flags.append(get_llvm_config_output('--system-libs')) + + print(' '.join(all_flags)) + +if __name__ == '__main__': + main()