+from __future__ import absolute_import
import os
import sys
-import componentinfo
-import configutil
+import llvmbuild.componentinfo as componentinfo
+import llvmbuild.configutil as configutil
-from util import *
+from llvmbuild.util import fatal, note
###
return value
+def cmake_quote_path(value):
+ """
+ cmake_quote_path(value) -> str
+
+ Return a quoted form of the given value that is suitable for use in CMake
+ language files.
+ """
+
+ # CMake has a bug in it's Makefile generator that doesn't properly quote
+ # strings it generates. So instead of using proper quoting, we just use "/"
+ # style paths. Currently, we only handle escaping backslashes.
+ value = value.replace("\\", "/")
+
+ return value
+
def mk_quote_string_for_target(value):
"""
mk_quote_string_for_target(target_name) -> str
Create the given directory path for installation, including any parents.
"""
- # os.makedirs considers it an error to be called with an existant path.
+ # os.makedirs considers it an error to be called with an existent path.
if not os.path.exists(path):
os.makedirs(path)
class LLVMProjectInfo(object):
@staticmethod
def load_infos_from_path(llvmbuild_source_root):
- # FIXME: Implement a simple subpath file list cache, so we don't restat
- # directories we have already traversed.
+ def recurse(subpath):
+ # Load the LLVMBuild file.
+ llvmbuild_path = os.path.join(llvmbuild_source_root + subpath,
+ 'LLVMBuild.txt')
+ if not os.path.exists(llvmbuild_path):
+ fatal("missing LLVMBuild.txt file at: %r" % (llvmbuild_path,))
+
+ # Parse the components from it.
+ common,info_iter = componentinfo.load_from_path(llvmbuild_path,
+ subpath)
+ for info in info_iter:
+ yield info
- # First, discover all the LLVMBuild.txt files.
- #
- # FIXME: We would like to use followlinks=True here, but that isn't
- # compatible with Python 2.4. Instead, we will either have to special
- # case projects we would expect to possibly be linked to, or implement
- # our own walk that can follow links. For now, it doesn't matter since
- # we haven't picked up the LLVMBuild system in any other LLVM projects.
- for dirpath,dirnames,filenames in os.walk(llvmbuild_source_root):
- # If there is no LLVMBuild.txt file in a directory, we don't recurse
- # past it. This is a simple way to prune our search, although it
- # makes it easy for users to add LLVMBuild.txt files in places they
- # won't be seen.
- if 'LLVMBuild.txt' not in filenames:
- del dirnames[:]
- continue
+ # Recurse into the specified subdirectories.
+ for subdir in common.get_list("subdirectories"):
+ for item in recurse(os.path.join(subpath, subdir)):
+ yield item
- # Otherwise, load the LLVMBuild file in this directory.
- assert dirpath.startswith(llvmbuild_source_root)
- subpath = '/' + dirpath[len(llvmbuild_source_root)+1:]
- llvmbuild_path = os.path.join(dirpath, 'LLVMBuild.txt')
- for info in componentinfo.load_from_path(llvmbuild_path, subpath):
- yield info
+ return recurse("/")
@staticmethod
def load_from_path(source_root, llvmbuild_source_root):
# out easily. If we don't, we should special case the check.
self.ordered_component_infos = []
- components_to_visit = set(self.component_infos)
+ components_to_visit = sorted(
+ set(self.component_infos),
+ key = lambda c: c.name)
while components_to_visit:
- visit_component_info(iter(components_to_visit).next(), [], set())
+ visit_component_info(components_to_visit[0], [], set())
# Canonicalize children lists.
for c in self.ordered_component_infos:
def print_tree(self):
def visit(node, depth = 0):
- print '%s%-40s (%s)' % (' '*depth, node.name, node.type_name)
+ print('%s%-40s (%s)' % (' '*depth, node.name, node.type_name))
for c in node.children:
visit(c, depth + 1)
visit(self.component_info_map['$ROOT'])
info_basedir[ci.subpath] = info_basedir.get(ci.subpath, []) + [ci]
+ # Compute the list of subdirectories to scan.
+ subpath_subdirs = {}
+ for ci in self.component_infos:
+ # Ignore root components.
+ if ci.subpath == '/':
+ continue
+
+ # Otherwise, append this subpath to the parent list.
+ parent_path = os.path.dirname(ci.subpath)
+ subpath_subdirs[parent_path] = parent_list = subpath_subdirs.get(
+ parent_path, set())
+ parent_list.add(os.path.basename(ci.subpath))
+
# Generate the build files.
for subpath, infos in info_basedir.items():
# Order the components by name to have a canonical ordering.
infos.sort(key = lambda ci: ci.name)
# Format the components into llvmbuild fragments.
- fragments = filter(None, [ci.get_llvmbuild_fragment()
- for ci in infos])
+ fragments = []
+
+ # Add the common fragments.
+ subdirectories = subpath_subdirs.get(subpath)
+ if subdirectories:
+ fragment = """\
+subdirectories = %s
+""" % (" ".join(sorted(subdirectories)),)
+ fragments.append(("common", fragment))
+
+ # Add the component fragments.
+ num_common_fragments = len(fragments)
+ for ci in infos:
+ fragment = ci.get_llvmbuild_fragment()
+ if fragment is None:
+ continue
+
+ name = "component_%d" % (len(fragments) - num_common_fragments)
+ fragments.append((name, fragment))
+
if not fragments:
continue
if not os.path.exists(directory_path):
os.makedirs(directory_path)
- # Create the LLVMBuild file.
+ # In an effort to preserve comments (which aren't parsed), read in
+ # the original file and extract the comments. We only know how to
+ # associate comments that prefix a section name.
+ f = open(infos[0]._source_path)
+ comments_map = {}
+ comment_block = ""
+ for ln in f:
+ if ln.startswith(';'):
+ comment_block += ln
+ elif ln.startswith('[') and ln.endswith(']\n'):
+ comments_map[ln[1:-2]] = comment_block
+ else:
+ comment_block = ""
+ f.close()
+
+ # Create the LLVMBuild fil[e.
file_path = os.path.join(directory_path, 'LLVMBuild.txt')
f = open(file_path, "w")
header_name = '.' + os.path.join(subpath, 'LLVMBuild.txt')
header_pad = '-' * (80 - len(header_fmt % (header_name, '')))
header_string = header_fmt % (header_name, header_pad)
- print >>f, """\
+ f.write("""\
%s
;
; The LLVM Compiler Infrastructure
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
-""" % header_string
- for i,fragment in enumerate(fragments):
- print >>f, '[component_%d]' % i
+""" % header_string)
+
+ # Write out each fragment.each component fragment.
+ for name,fragment in fragments:
+ comment = comments_map.get(name)
+ if comment is not None:
+ f.write(comment)
+ f.write("[%s]\n" % name)
f.write(fragment)
- print >>f
+ if fragment is not fragments[-1][1]:
+ f.write('\n')
+
f.close()
- def write_library_table(self, output_path):
+ def write_library_table(self, output_path, enabled_optional_components):
# Write out the mapping from component names to required libraries.
#
# We do this in topological order so that we know we can append the
# dependencies for added library groups.
entries = {}
for c in self.ordered_component_infos:
+ # Skip optional components which are not enabled.
+ if c.type_name == 'OptionalLibrary' \
+ and c.name not in enabled_optional_components:
+ continue
+
+ # Skip target groups which are not enabled.
+ tg = c.get_parent_target_group()
+ if tg and not tg.enabled:
+ continue
+
# Only certain components are in the table.
- if c.type_name not in ('Library', 'LibraryGroup', 'TargetGroup'):
+ if c.type_name not in ('Library', 'OptionalLibrary', \
+ 'LibraryGroup', 'TargetGroup'):
continue
# Compute the llvm-config "component name". For historical reasons,
llvmconfig_component_name = c.get_llvmconfig_component_name()
# Get the library name, or None for LibraryGroups.
- if c.type_name == 'Library':
- library_name = c.get_library_name()
+ if c.type_name == 'Library' or c.type_name == 'OptionalLibrary':
+ library_name = c.get_prefixed_library_name()
+ is_installed = c.installed
else:
library_name = None
+ is_installed = True
# Get the component names of all the required libraries.
required_llvmconfig_component_names = [
# Add the entry.
entries[c.name] = (llvmconfig_component_name, library_name,
- required_llvmconfig_component_names)
+ required_llvmconfig_component_names,
+ is_installed)
# Convert to a list of entries and sort by name.
- entries = entries.values()
+ entries = list(entries.values())
# Create an 'all' pseudo component. We keep the dependency list small by
# only listing entries that have no other dependents.
root_entries = set(e[0] for e in entries)
- for _,_,deps in entries:
+ for _,_,deps,_ in entries:
root_entries -= set(deps)
- entries.append(('all', None, root_entries))
+ entries.append(('all', None, root_entries, True))
entries.sort()
# Compute the maximum number of required libraries, plus one so there is
# always a sentinel.
max_required_libraries = max(len(deps)
- for _,_,deps in entries) + 1
+ for _,_,deps,_ in entries) + 1
# Write out the library table.
make_install_dir(os.path.dirname(output_path))
f = open(output_path, 'w')
- print >>f, """\
+ f.write("""\
//===- llvm-build generated file --------------------------------*- C++ -*-===//
//
// Component Library Depenedency Table
// Automatically generated file, do not edit!
//
//===----------------------------------------------------------------------===//
-"""
- print >>f, 'struct AvailableComponent {'
- print >>f, ' /// The name of the component.'
- print >>f, ' const char *Name;'
- print >>f, ''
- print >>f, ' /// The name of the library for this component (or NULL).'
- print >>f, ' const char *Library;'
- print >>f, ''
- print >>f, '\
- /// The list of libraries required when linking this component.'
- print >>f, ' const char *RequiredLibraries[%d];' % (
- max_required_libraries)
- print >>f, '} AvailableComponents[%d] = {' % len(entries)
- for name,library_name,required_names in entries:
+
+""")
+ f.write('struct AvailableComponent {\n')
+ f.write(' /// The name of the component.\n')
+ f.write(' const char *Name;\n')
+ f.write('\n')
+ f.write(' /// The name of the library for this component (or NULL).\n')
+ f.write(' const char *Library;\n')
+ f.write('\n')
+ f.write(' /// Whether the component is installed.\n')
+ f.write(' bool IsInstalled;\n')
+ f.write('\n')
+ f.write('\
+ /// The list of libraries required when linking this component.\n')
+ f.write(' const char *RequiredLibraries[%d];\n' % (
+ max_required_libraries))
+ f.write('} AvailableComponents[%d] = {\n' % len(entries))
+ for name,library_name,required_names,is_installed in entries:
if library_name is None:
library_name_as_cstr = '0'
else:
- # If we had a project level component, we could derive the
- # library prefix.
- library_name_as_cstr = '"libLLVM%s.a"' % library_name
- print >>f, ' { "%s", %s, { %s } },' % (
- name, library_name_as_cstr,
+ library_name_as_cstr = '"lib%s.a"' % library_name
+ f.write(' { "%s", %s, %d, { %s } },\n' % (
+ name, library_name_as_cstr, is_installed,
', '.join('"%s"' % dep
- for dep in required_names))
- print >>f, '};'
+ for dep in required_names)))
+ f.write('};\n')
f.close()
+ def get_required_libraries_for_component(self, ci, traverse_groups = False):
+ """
+ get_required_libraries_for_component(component_info) -> iter
+
+ Given a Library component info descriptor, return an iterator over all
+ of the directly required libraries for linking with this component. If
+ traverse_groups is True, then library and target groups will be
+ traversed to include their required libraries.
+ """
+
+ assert ci.type_name in ('Library', 'LibraryGroup', 'TargetGroup')
+
+ for name in ci.required_libraries:
+ # Get the dependency info.
+ dep = self.component_info_map[name]
+
+ # If it is a library, yield it.
+ if dep.type_name == 'Library':
+ yield dep
+ continue
+
+ # Otherwise if it is a group, yield or traverse depending on what
+ # was requested.
+ if dep.type_name in ('LibraryGroup', 'TargetGroup'):
+ if not traverse_groups:
+ yield dep
+ continue
+
+ for res in self.get_required_libraries_for_component(dep, True):
+ yield res
+
def get_fragment_dependencies(self):
"""
get_fragment_dependencies() -> iter
# Construct a list of all the dependencies of the Makefile fragment
# itself. These include all the LLVMBuild files themselves, as well as
# all of our own sources.
+ #
+ # Many components may come from the same file, so we make sure to unique
+ # these.
+ build_paths = set()
for ci in self.component_infos:
- yield os.path.join(self.source_root, ci.subpath[1:],
- 'LLVMBuild.txt')
+ p = os.path.join(self.source_root, ci.subpath[1:], 'LLVMBuild.txt')
+ if p not in build_paths:
+ yield p
+ build_paths.add(p)
# Gather the list of necessary sources by just finding all loaded
# modules that are inside the LLVM source tree.
header_name = os.path.basename(output_path)
header_pad = '-' * (80 - len(header_fmt % (header_name, '')))
header_string = header_fmt % (header_name, header_pad)
- print >>f, """\
+ f.write("""\
%s
#
# The LLVM Compiler Infrastructure
# This file is autogenerated by llvm-build, do not edit!
#
#===------------------------------------------------------------------------===#
-""" % header_string
+
+""" % header_string)
# Write the dependency information in the best way we can.
- print >>f, """
+ f.write("""
# LLVMBuild CMake fragment dependencies.
#
# CMake has no builtin way to declare that the configuration depends on
# CMake.
#
# FIXME: File a CMake RFE to get a properly supported version of this
-# feature."""
+# feature.
+""")
for dep in dependencies:
- print >>f, """\
+ f.write("""\
configure_file(\"%s\"
- ${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)""" % (
- cmake_quote_string(dep),)
+ ${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)\n""" % (
+ cmake_quote_path(dep),))
+
+ # Write the properties we use to encode the required library dependency
+ # information in a form CMake can easily use directly.
+ f.write("""
+# Explicit library dependency information.
+#
+# The following property assignments effectively create a map from component
+# names to required libraries, in a way that is easily accessed from CMake.
+""")
+ for ci in self.ordered_component_infos:
+ # We only write the information for libraries currently.
+ if ci.type_name != 'Library':
+ continue
+
+ f.write("""\
+set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)\n""" % (
+ ci.get_prefixed_library_name(), " ".join(sorted(
+ dep.get_prefixed_library_name()
+ for dep in self.get_required_libraries_for_component(ci)))))
+
+ f.close()
+
+ def write_cmake_exports_fragment(self, output_path):
+ """
+ write_cmake_exports_fragment(output_path) -> None
+
+ Generate a CMake fragment which includes LLVMBuild library
+ dependencies expressed similarly to how CMake would write
+ them via install(EXPORT).
+ """
+
+ dependencies = list(self.get_fragment_dependencies())
+
+ # Write out the CMake exports fragment.
+ make_install_dir(os.path.dirname(output_path))
+ f = open(output_path, 'w')
+
+ f.write("""\
+# Explicit library dependency information.
+#
+# The following property assignments tell CMake about link
+# dependencies of libraries imported from LLVM.
+""")
+ for ci in self.ordered_component_infos:
+ # We only write the information for libraries currently.
+ if ci.type_name != 'Library':
+ continue
+
+ # Skip disabled targets.
+ tg = ci.get_parent_target_group()
+ if tg and not tg.enabled:
+ continue
+
+ f.write("""\
+set_property(TARGET %s PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES %s)\n""" % (
+ ci.get_prefixed_library_name(), " ".join(sorted(
+ dep.get_prefixed_library_name()
+ for dep in self.get_required_libraries_for_component(ci)))))
f.close()
header_name = os.path.basename(output_path)
header_pad = '-' * (80 - len(header_fmt % (header_name, '')))
header_string = header_fmt % (header_name, header_pad)
- print >>f, """\
+ f.write("""\
%s
#
# The LLVM Compiler Infrastructure
# This file is autogenerated by llvm-build, do not edit!
#
#===------------------------------------------------------------------------===#
-""" % header_string
+
+""" % header_string)
# Write the dependencies for the fragment.
#
# FIXME: Technically, we need to properly quote for Make here.
- print >>f, """\
+ f.write("""\
# Clients must explicitly enable LLVMBUILD_INCLUDE_DEPENDENCIES to get
# these dependencies. This is a compromise to help improve the
-# performance of recursive Make systems."""
- print >>f, 'ifeq ($(LLVMBUILD_INCLUDE_DEPENDENCIES),1)'
- print >>f, "# The dependencies for this Makefile fragment itself."
- print >>f, "%s: \\" % (mk_quote_string_for_target(output_path),)
+# performance of recursive Make systems.
+""")
+ f.write('ifeq ($(LLVMBUILD_INCLUDE_DEPENDENCIES),1)\n')
+ f.write("# The dependencies for this Makefile fragment itself.\n")
+ f.write("%s: \\\n" % (mk_quote_string_for_target(output_path),))
for dep in dependencies:
- print >>f, "\t%s \\" % (dep,)
- print >>f
+ f.write("\t%s \\\n" % (dep,))
+ f.write('\n')
# Generate dummy rules for each of the dependencies, so that things
# continue to work correctly if any of those files are moved or removed.
- print >>f, """\
+ f.write("""\
# The dummy targets to allow proper regeneration even when files are moved or
-# removed."""
+# removed.
+""")
for dep in dependencies:
- print >>f, "%s:" % (mk_quote_string_for_target(dep),)
- print >>f, 'endif'
+ f.write("%s:\n" % (mk_quote_string_for_target(dep),))
+ f.write('endif\n')
f.close()
enable_targets = available_targets.values()
else:
# We support both space separated and semi-colon separated lists.
- if ' ' in opts.enable_targets:
+ if opts.enable_targets == '':
+ enable_target_names = []
+ elif ' ' in opts.enable_targets:
enable_target_names = opts.enable_targets.split()
else:
enable_target_names = opts.enable_targets.split(';')
fatal("special component %r must have empty %r list" % (
name, 'add_to_library_groups'))
+ info._is_special_group = True
return info
info_map = dict((ci.name, ci) for ci in project.component_infos)
# If we have a native target with a JIT, use that for the engine. Otherwise,
# use the interpreter.
if native_target and native_target.enabled and native_target.has_jit:
- engine_group.required_libraries.append('JIT')
+ engine_group.required_libraries.append('MCJIT')
engine_group.required_libraries.append(native_group.name)
else:
engine_group.required_libraries.append('Interpreter')
dest="write_cmake_fragment", metavar="PATH",
help="Write the CMake project information to PATH",
action="store", default=None)
+ group.add_option("", "--write-cmake-exports-fragment",
+ dest="write_cmake_exports_fragment", metavar="PATH",
+ help="Write the CMake exports information to PATH",
+ action="store", default=None)
group.add_option("", "--write-make-fragment",
dest="write_make_fragment", metavar="PATH",
help="Write the Makefile project information to PATH",
help=("Enable the given space or semi-colon separated "
"list of targets, or all targets if not present"),
action="store", default=None)
+ group.add_option("", "--enable-optional-components",
+ dest="optional_components", metavar="NAMES",
+ help=("Enable the given space or semi-colon separated "
+ "list of optional components"),
+ action="store", default="")
parser.add_option_group(group)
(opts, args) = parser.parse_args()
# Determine the LLVM source path, if not given.
source_root = opts.source_root
if source_root:
- if not os.path.exists(os.path.join(source_root, 'lib', 'VMCore',
+ if not os.path.exists(os.path.join(source_root, 'lib', 'IR',
'Function.cpp')):
parser.error('invalid LLVM source root: %r' % source_root)
else:
llvm_build_path = os.path.dirname(llvmbuild_path)
utils_path = os.path.dirname(llvm_build_path)
source_root = os.path.dirname(utils_path)
- if not os.path.exists(os.path.join(source_root, 'lib', 'VMCore',
+ if not os.path.exists(os.path.join(source_root, 'lib', 'IR',
'Function.cpp')):
parser.error('unable to infer LLVM source root, please specify')
# Write out the required library table, if requested.
if opts.write_library_table:
- project_info.write_library_table(opts.write_library_table)
+ project_info.write_library_table(opts.write_library_table,
+ opts.optional_components)
# Write out the make fragment, if requested.
if opts.write_make_fragment:
# Write out the cmake fragment, if requested.
if opts.write_cmake_fragment:
project_info.write_cmake_fragment(opts.write_cmake_fragment)
+ if opts.write_cmake_exports_fragment:
+ project_info.write_cmake_exports_fragment(opts.write_cmake_exports_fragment)
# Configure target definition files, if requested.
if opts.configure_target_def_files: