# -*- python -*- import os.path from distutils.version import LooseVersion import re import subprocess Import('env testruns') dist_headers = [ "hammer.h", "allocator.h", "compiler_specifics.h", "glue.h", "internal.h", "platform.h" ] parsers_headers = [ "parsers/parser_internal.h" ] backends_headers = [ "backends/regex.h", "backends/contextfree.h" ] parsers = ['parsers/%s.c'%s for s in ['action', 'and', 'attr_bool', 'bind', 'bits', 'butnot', 'ch', 'charset', 'choice', 'difference', 'end', 'endianness', 'epsilon', 'ignore', 'ignoreseq', 'indirect', 'int_range', 'many', 'not', 'nothing', 'optional', 'permutation', 'sequence', 'token', 'unimplemented', 'whitespace', 'xor', 'value']] backends = ['backends/%s.c' % s for s in ['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0', 'llvm']] misc_hammer_parts = [ 'allocator.c', 'benchmark.c', 'bitreader.c', 'bitwriter.c', 'cfgrammar.c', 'datastructures.c', 'desugar.c', 'glue.c', 'hammer.c', 'platform_bsdlike.c', 'pprint.c', 'registry.c', 'system_allocator.c'] ctests = ['t_benchmark.c', 't_bitreader.c', 't_bitwriter.c', 't_parser.c', 't_grammar.c', 't_misc.c', 't_regression.c'] # some llvm versions are old and will not work; some require --system-libs # with llvm-config, and some will break if given it llvm_config_version = subprocess.Popen('%s --version' % env["LLVM_CONFIG"], \ shell=True, \ stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate() if LooseVersion(llvm_config_version[0]) < LooseVersion("3.6"): print "This LLVM version %s is too old" % llvm_config_version Exit(1) if LooseVersion(llvm_config_version[0]) < LooseVersion("3.9") and \ LooseVersion(llvm_config_version[0]) >= LooseVersion("3.5"): llvm_system_libs_flag = "--system-libs" else: llvm_system_libs_flag = "" # Only keep one copy of this required_llvm_components = "core executionengine mcjit analysis x86codegen x86info" # Stubbing this out so we can implement static-only mode if needed later use_shared_llvm = True # Can we ask for shared/static from llvm-config? if LooseVersion(llvm_config_version[0]) < LooseVersion("3.9"): # Nope llvm_linkage_type_flag = "" llvm_use_computed_shared_lib_name = True else: # Woo, they finally fixed the dumb llvm_use_computed_shared_lib_name = False if use_shared_llvm: llvm_linkage_type_flag = "--link-shared" else: llvm_linkage_type_flag = "--link-static" if llvm_use_computed_shared_lib_name: # Okay, pull out the major and minor version numbers (barf barf) p = re.compile("^(\d+)\.(\d+).*$") m = p.match(llvm_config_version[0]) if m: llvm_computed_shared_lib_name = "LLVM-%d.%d" % ((int)(m.group(1)), (int)(m.group(2))) else: print "Couldn't compute shared library name from LLVM version '%s', but needed to" % \ llvm_config_version[0] Exit(1) else: # We won't be needing it llvm_computed_shared_lib_name = None # llvm-config 'helpfully' supplies -g and -O flags; educate it with this # custom ParseConfig function arg def llvm_config_sanitize(env, cmd, unique=1): # cmd is output from llvm-config flags = cmd.split() # match -g or -O flags p = re.compile("^-[gO].*$") filtered_flags = [flag for flag in flags if not p.match(flag)] filtered_cmd = ' '.join(filtered_flags) # print "llvm_config_sanitize: \"%s\" => \"%s\"" % (cmd, filtered_cmd) env.MergeFlags(filtered_cmd, unique) env.ParseConfig('%s --cflags --ldflags' % env["LLVM_CONFIG"], function=llvm_config_sanitize) libhammer_static = env.StaticLibrary('hammer', parsers + backends + misc_hammer_parts) # Use a cloned env for the shared library so we can have library dependencies shared_env = env.Clone() # Get LLVM stuff into LIBS/LDFLAGS shared_env.ParseConfig('%s --ldflags %s %s %s' % \ (env["LLVM_CONFIG"], llvm_system_libs_flag, llvm_linkage_type_flag, required_llvm_components), \ function=llvm_config_sanitize) # Get the right -l lines in if use_shared_llvm: if llvm_use_computed_shared_lib_name: shared_env.Append(LIBS=[llvm_computed_shared_lib_name, ]) else: shared_env.ParseConfig('%s %s --libs %s' % \ (env["LLVM_CONFIG"], llvm_linkage_type_flag, required_llvm_components), \ function=llvm_config_sanitize) else: # Just grab the statics regardless of version shared_env.ParseConfig('%s %s --libs %s' % \ (env["LLVM_CONFIG"], llvm_linkage_type_flag, required_llvm_components), \ function=llvm_config_sanitize) shared_env.Append(LIBS=['stdc++', ], LIBPATH=['.']) libhammer_shared = shared_env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts) Default(libhammer_shared, libhammer_static) env.Install("$libpath", [libhammer_static, libhammer_shared]) env.Install("$incpath", dist_headers) env.Install("$parsersincpath", parsers_headers) env.Install("$backendsincpath", backends_headers) env.Install("$pkgconfigpath", "../../../libhammer.pc") testenv = env.Clone() testenv.Append(LIBS=['hammer'], LIBPATH=['.']) testenv.ParseConfig('pkg-config --cflags --libs glib-2.0') # Get LLVM stuff into LIBS/LDFLAGS testenv.ParseConfig('%s --ldflags %s %s %s' % \ (env["LLVM_CONFIG"], llvm_system_libs_flag, llvm_linkage_type_flag, required_llvm_components), \ function=llvm_config_sanitize) # Get the right -l lines in if use_shared_llvm: if llvm_use_computed_shared_lib_name: testenv.Append(LIBS=[llvm_computed_shared_lib_name, ]) else: testenv.ParseConfig('%s %s --libs %s' % \ (env["LLVM_CONFIG"], llvm_linkage_type_flag, required_llvm_components), \ function=llvm_config_sanitize) else: # Just grab the statics regardless of version testenv.ParseConfig('%s %s --libs %s' % \ (env["LLVM_CONFIG"], llvm_linkage_type_flag, required_llvm_components), \ function=llvm_config_sanitize) testenv.Append(LIBS=['stdc++'], LIBPATH=['.']) ctestexec = testenv.Program('test_suite', ctests + ['test_suite.c'], LINKFLAGS="--coverage" if testenv.GetOption("coverage") else None) ctest = Alias('testc', [ctestexec], "".join(["env LD_LIBRARY_PATH=", os.path.dirname(ctestexec[0].path), " ", ctestexec[0].path])) AlwaysBuild(ctest) testruns.append(ctest) Export("libhammer_static libhammer_shared") for b in env['bindings']: env.SConscript(["bindings/%s/SConscript" % b])