[NFC][Py Reformat] Reformat python files in libcxx/libcxxabi
This is an ongoing series of commits that are reformatting our Python code. Reformatting is done with `black`. If you end up having problems merging this commit because you have made changes to a python file, the best way to handle that is to run git checkout --ours <yourfile> and then reformat it with black. If you run into any problems, post to discourse about it and we will try to help. RFC Thread below: https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style Reviewed By: #libc, kwk, Mordante Differential Revision: https://reviews.llvm.org/D150763
This commit is contained in:
parent
2ba14283cd
commit
7bfaa0f09d
@ -3,21 +3,21 @@
|
|||||||
import os
|
import os
|
||||||
import site
|
import site
|
||||||
|
|
||||||
site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'utils'))
|
site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(__file__)), "utils"))
|
||||||
from libcxx.test.googlebenchmark import GoogleBenchmark
|
from libcxx.test.googlebenchmark import GoogleBenchmark
|
||||||
|
|
||||||
# Tell pylint that we know config and lit_config exist somewhere.
|
# Tell pylint that we know config and lit_config exist somewhere.
|
||||||
if 'PYLINT_IMPORT' in os.environ:
|
if "PYLINT_IMPORT" in os.environ:
|
||||||
config = object()
|
config = object()
|
||||||
lit_config = object()
|
lit_config = object()
|
||||||
|
|
||||||
# name: The name of this test suite.
|
# name: The name of this test suite.
|
||||||
config.name = 'libc++ benchmarks'
|
config.name = "libc++ benchmarks"
|
||||||
config.suffixes = []
|
config.suffixes = []
|
||||||
|
|
||||||
config.test_exec_root = os.path.join(config.libcxx_obj_root, 'benchmarks')
|
config.test_exec_root = os.path.join(config.libcxx_obj_root, "benchmarks")
|
||||||
config.test_source_root = config.test_exec_root
|
config.test_source_root = config.test_exec_root
|
||||||
|
|
||||||
config.test_format = GoogleBenchmark(test_sub_dirs='.',
|
config.test_format = GoogleBenchmark(
|
||||||
test_suffix='.libcxx.out',
|
test_sub_dirs=".", test_suffix=".libcxx.out", benchmark_args=config.benchmark_args
|
||||||
benchmark_args=config.benchmark_args)
|
)
|
||||||
|
@ -16,106 +16,106 @@ from datetime import date
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#sys.path.insert(0, os.path.abspath('.'))
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
#needs_sphinx = '1.0'
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
|
extensions = ["sphinx.ext.intersphinx", "sphinx.ext.todo"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = '.rst'
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
#source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'libc++'
|
project = "libc++"
|
||||||
copyright = u'2011-%d, LLVM Project' % date.today().year
|
copyright = "2011-%d, LLVM Project" % date.today().year
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '17.0'
|
version = "17.0"
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '17.0'
|
release = "17.0"
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
#language = None
|
# language = None
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
#today = ''
|
# today = ''
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
today_fmt = '%Y-%m-%d'
|
today_fmt = "%Y-%m-%d"
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
exclude_patterns = ['_build', 'Helpers']
|
exclude_patterns = ["_build", "Helpers"]
|
||||||
|
|
||||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
#default_role = None
|
# default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
#add_function_parentheses = True
|
# add_function_parentheses = True
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
#add_module_names = True
|
# add_module_names = True
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
show_authors = True
|
show_authors = True
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
pygments_style = 'friendly'
|
pygments_style = "friendly"
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
# A list of ignored prefixes for module index sorting.
|
||||||
#modindex_common_prefix = []
|
# modindex_common_prefix = []
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output ---------------------------------------------------
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'haiku'
|
html_theme = "haiku"
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
#html_theme_options = {}
|
# html_theme_options = {}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
#html_theme_path = []
|
# html_theme_path = []
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
#html_title = None
|
# html_title = None
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
#html_short_title = None
|
# html_short_title = None
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
# of the sidebar.
|
# of the sidebar.
|
||||||
#html_logo = None
|
# html_logo = None
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
# pixels large.
|
# pixels large.
|
||||||
#html_favicon = None
|
# html_favicon = None
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
@ -124,101 +124,95 @@ html_static_path = []
|
|||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
# using the given strftime format.
|
# using the given strftime format.
|
||||||
#html_last_updated_fmt = '%b %d, %Y'
|
# html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
#html_use_smartypants = True
|
# html_use_smartypants = True
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
#html_sidebars = {}
|
# html_sidebars = {}
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
# template names.
|
# template names.
|
||||||
#html_additional_pages = {}
|
# html_additional_pages = {}
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#html_domain_indices = True
|
# html_domain_indices = True
|
||||||
|
|
||||||
# If false, no index is generated.
|
# If false, no index is generated.
|
||||||
#html_use_index = True
|
# html_use_index = True
|
||||||
|
|
||||||
# If true, the index is split into individual pages for each letter.
|
# If true, the index is split into individual pages for each letter.
|
||||||
#html_split_index = False
|
# html_split_index = False
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
# If true, links to the reST sources are added to the pages.
|
||||||
#html_show_sourcelink = True
|
# html_show_sourcelink = True
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
#html_show_sphinx = True
|
# html_show_sphinx = True
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
#html_show_copyright = True
|
# html_show_copyright = True
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
# base URL from which the finished HTML is served.
|
# base URL from which the finished HTML is served.
|
||||||
#html_use_opensearch = ''
|
# html_use_opensearch = ''
|
||||||
|
|
||||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
#html_file_suffix = None
|
# html_file_suffix = None
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'libcxxdoc'
|
htmlhelp_basename = "libcxxdoc"
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output --------------------------------------------------
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
#'papersize': 'letterpaper',
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
#'pointsize': '10pt',
|
||||||
#'pointsize': '10pt',
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#'preamble': '',
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
#'preamble': '',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('contents', 'libcxx.tex', u'libcxx Documentation',
|
("contents", "libcxx.tex", "libcxx Documentation", "LLVM project", "manual"),
|
||||||
u'LLVM project', 'manual'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
# the title page.
|
# the title page.
|
||||||
#latex_logo = None
|
# latex_logo = None
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
# not chapters.
|
# not chapters.
|
||||||
#latex_use_parts = False
|
# latex_use_parts = False
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
# If true, show page references after internal links.
|
||||||
#latex_show_pagerefs = False
|
# latex_show_pagerefs = False
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#latex_show_urls = False
|
# latex_show_urls = False
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
#latex_appendices = []
|
# latex_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#latex_domain_indices = True
|
# latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output --------------------------------------------
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [("contents", "libc++", "libc++ Documentation", ["LLVM project"], 1)]
|
||||||
('contents', 'libc++', u'libc++ Documentation',
|
|
||||||
[u'LLVM project'], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#man_show_urls = False
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ------------------------------------------------
|
# -- Options for Texinfo output ------------------------------------------------
|
||||||
@ -227,19 +221,25 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('contents', 'libc++', u'libc++ Documentation',
|
(
|
||||||
u'LLVM project', 'libc++', 'One line description of project.',
|
"contents",
|
||||||
'Miscellaneous'),
|
"libc++",
|
||||||
|
"libc++ Documentation",
|
||||||
|
"LLVM project",
|
||||||
|
"libc++",
|
||||||
|
"One line description of project.",
|
||||||
|
"Miscellaneous",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
#texinfo_appendices = []
|
# texinfo_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#texinfo_domain_indices = True
|
# texinfo_domain_indices = True
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
#texinfo_show_urls = 'footnote'
|
# texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
|
||||||
# FIXME: Define intersphinx configuration.
|
# FIXME: Define intersphinx configuration.
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# Disable all of the experimental tests if the correct feature is not available.
|
# Disable all of the experimental tests if the correct feature is not available.
|
||||||
if 'c++experimental' not in config.available_features:
|
if "c++experimental" not in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
"""Commands used to automate testing gdb pretty printers.
|
"""Commands used to automate testing gdb pretty printers.
|
||||||
|
|
||||||
This script is part of a larger framework to test gdb pretty printers. It
|
This script is part of a larger framework to test gdb pretty printers. It
|
||||||
@ -31,10 +31,8 @@ has_run_tests = False
|
|||||||
|
|
||||||
|
|
||||||
class CheckResult(gdb.Command):
|
class CheckResult(gdb.Command):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CheckResult, self).__init__(
|
super(CheckResult, self).__init__("print_and_compare", gdb.COMMAND_DATA)
|
||||||
"print_and_compare", gdb.COMMAND_DATA)
|
|
||||||
|
|
||||||
def invoke(self, arg, from_tty):
|
def invoke(self, arg, from_tty):
|
||||||
global has_run_tests
|
global has_run_tests
|
||||||
@ -55,7 +53,7 @@ class CheckResult(gdb.Command):
|
|||||||
value_str = self._get_value_string(compare_frame, testcase_frame)
|
value_str = self._get_value_string(compare_frame, testcase_frame)
|
||||||
|
|
||||||
# Ignore the convenience variable name and newline
|
# Ignore the convenience variable name and newline
|
||||||
value = value_str[value_str.find("= ") + 2:-1]
|
value = value_str[value_str.find("= ") + 2 : -1]
|
||||||
gdb.newest_frame().select()
|
gdb.newest_frame().select()
|
||||||
expectation_val = compare_frame.read_var("expectation")
|
expectation_val = compare_frame.read_var("expectation")
|
||||||
check_literal = expectation_val.string(encoding="utf-8")
|
check_literal = expectation_val.string(encoding="utf-8")
|
||||||
@ -66,16 +64,14 @@ class CheckResult(gdb.Command):
|
|||||||
|
|
||||||
if test_fails:
|
if test_fails:
|
||||||
global test_failures
|
global test_failures
|
||||||
print("FAIL: " + test_loc.symtab.filename +
|
print("FAIL: " + test_loc.symtab.filename + ":" + str(test_loc.line))
|
||||||
":" + str(test_loc.line))
|
|
||||||
print("GDB printed:")
|
print("GDB printed:")
|
||||||
print(" " + repr(value))
|
print(" " + repr(value))
|
||||||
print("Value should match:")
|
print("Value should match:")
|
||||||
print(" " + repr(check_literal))
|
print(" " + repr(check_literal))
|
||||||
test_failures += 1
|
test_failures += 1
|
||||||
else:
|
else:
|
||||||
print("PASS: " + test_loc.symtab.filename +
|
print("PASS: " + test_loc.symtab.filename + ":" + str(test_loc.line))
|
||||||
":" + str(test_loc.line))
|
|
||||||
|
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
# At this point, lots of different things could be wrong, so don't try to
|
# At this point, lots of different things could be wrong, so don't try to
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
# Load the same local configuration as the filesystem tests in libcxx/test/std
|
# Load the same local configuration as the filesystem tests in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
std_filesystem_tests = os.path.join(config.test_source_root, 'std', 'input.output', 'filesystems')
|
|
||||||
config.load_from_path(os.path.join(std_filesystem_tests, 'lit.local.cfg'), lit_config)
|
std_filesystem_tests = os.path.join(
|
||||||
|
config.test_source_root, "std", "input.output", "filesystems"
|
||||||
|
)
|
||||||
|
config.load_from_path(os.path.join(std_filesystem_tests, "lit.local.cfg"), lit_config)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -6,25 +6,25 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__))
|
libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__))
|
||||||
libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, '../../..'))
|
libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, "../../.."))
|
||||||
cmakelists_name = os.path.join(libcxx, 'include/CMakeLists.txt')
|
cmakelists_name = os.path.join(libcxx, "include/CMakeLists.txt")
|
||||||
assert os.path.isfile(cmakelists_name)
|
assert os.path.isfile(cmakelists_name)
|
||||||
|
|
||||||
with open(cmakelists_name, 'r') as f:
|
with open(cmakelists_name, "r") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
|
|
||||||
assert lines[0] == 'set(files\n'
|
assert lines[0] == "set(files\n"
|
||||||
|
|
||||||
okay = True
|
okay = True
|
||||||
prevline = lines[1]
|
prevline = lines[1]
|
||||||
for line in lines[2:]:
|
for line in lines[2:]:
|
||||||
if (line == ' )\n'):
|
if line == " )\n":
|
||||||
break
|
break
|
||||||
if (line < prevline):
|
if line < prevline:
|
||||||
okay = False
|
okay = False
|
||||||
print('LINES OUT OF ORDER in libcxx/include/CMakeLists.txt!')
|
print("LINES OUT OF ORDER in libcxx/include/CMakeLists.txt!")
|
||||||
print(prevline)
|
print(prevline)
|
||||||
print(line)
|
print(line)
|
||||||
prevline = line
|
prevline = line
|
||||||
|
@ -10,45 +10,52 @@ import re
|
|||||||
|
|
||||||
def exclude_from_consideration(path):
|
def exclude_from_consideration(path):
|
||||||
return (
|
return (
|
||||||
path.endswith('.txt') or
|
path.endswith(".txt")
|
||||||
path.endswith('.modulemap.in') or
|
or path.endswith(".modulemap.in")
|
||||||
os.path.basename(path) == '__config' or
|
or os.path.basename(path) == "__config"
|
||||||
os.path.basename(path) == '__config_site.in' or
|
or os.path.basename(path) == "__config_site.in"
|
||||||
os.path.basename(path) == 'libcxx.imp' or
|
or os.path.basename(path) == "libcxx.imp"
|
||||||
os.path.basename(path).startswith('__pstl') or # TODO: Remove once PSTL integration is finished
|
or os.path.basename(path).startswith("__pstl")
|
||||||
not os.path.isfile(path)
|
or not os.path.isfile(path) # TODO: Remove once PSTL integration is finished
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_for_pragma_GCC_system_header(pretty_fname, lines):
|
def check_for_pragma_GCC_system_header(pretty_fname, lines):
|
||||||
if pretty_fname not in ['__undef_macros']:
|
if pretty_fname not in ["__undef_macros"]:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if re.match('# *pragma GCC system_header\n', line):
|
if re.match("# *pragma GCC system_header\n", line):
|
||||||
return True
|
return True
|
||||||
print('FAILED TO FIND # pragma GCC system_header in libcxx/include/%s' % pretty_fname)
|
print(
|
||||||
|
"FAILED TO FIND # pragma GCC system_header in libcxx/include/%s"
|
||||||
|
% pretty_fname
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__))
|
libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__))
|
||||||
libcxx_include = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, '../../../include'))
|
libcxx_include = os.path.abspath(
|
||||||
|
os.path.join(libcxx_test_libcxx_lint, "../../../include")
|
||||||
|
)
|
||||||
assert os.path.isdir(libcxx_include)
|
assert os.path.isdir(libcxx_include)
|
||||||
|
|
||||||
def pretty(path):
|
def pretty(path):
|
||||||
return path[len(libcxx_include) + 1:]
|
return path[len(libcxx_include) + 1 :]
|
||||||
|
|
||||||
all_headers = [
|
all_headers = [
|
||||||
p for p in (
|
p
|
||||||
glob.glob(os.path.join(libcxx_include, '*')) +
|
for p in (
|
||||||
glob.glob(os.path.join(libcxx_include, '__*/*.h'))
|
glob.glob(os.path.join(libcxx_include, "*"))
|
||||||
) if not exclude_from_consideration(p)
|
+ glob.glob(os.path.join(libcxx_include, "__*/*.h"))
|
||||||
|
)
|
||||||
|
if not exclude_from_consideration(p)
|
||||||
]
|
]
|
||||||
|
|
||||||
okay = True
|
okay = True
|
||||||
for fname in all_headers:
|
for fname in all_headers:
|
||||||
pretty_fname = pretty(fname)
|
pretty_fname = pretty(fname)
|
||||||
with open(fname, 'r') as f:
|
with open(fname, "r") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
|
|
||||||
okay = check_for_pragma_GCC_system_header(pretty_fname, lines) and okay
|
okay = check_for_pragma_GCC_system_header(pretty_fname, lines) and okay
|
||||||
|
@ -7,39 +7,53 @@ import os
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__))
|
libcxx_test_libcxx_lint = os.path.dirname(os.path.abspath(__file__))
|
||||||
libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, '../../..'))
|
libcxx = os.path.abspath(os.path.join(libcxx_test_libcxx_lint, "../../.."))
|
||||||
modulemap_name = os.path.join(libcxx, 'include/module.modulemap.in')
|
modulemap_name = os.path.join(libcxx, "include/module.modulemap.in")
|
||||||
assert os.path.isfile(modulemap_name)
|
assert os.path.isfile(modulemap_name)
|
||||||
|
|
||||||
okay = True
|
okay = True
|
||||||
prevline = None
|
prevline = None
|
||||||
with open(modulemap_name, 'r') as f:
|
with open(modulemap_name, "r") as f:
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
if re.match(r'^\s*module.*[{]\s*private', line):
|
if re.match(r"^\s*module.*[{]\s*private", line):
|
||||||
# Check that these lines are all of the expected format.
|
# Check that these lines are all of the expected format.
|
||||||
# This incidentally checks for typos in the module name.
|
# This incidentally checks for typos in the module name.
|
||||||
if re.match(r'^\s*module (\w+)\s+[{] private header "\1(.h)?"\s+export [*] [}]', line):
|
if re.match(
|
||||||
|
r'^\s*module (\w+)\s+[{] private header "\1(.h)?"\s+export [*] [}]',
|
||||||
|
line,
|
||||||
|
):
|
||||||
# It's a top-level private header, such as <__bit_reference>.
|
# It's a top-level private header, such as <__bit_reference>.
|
||||||
pass
|
pass
|
||||||
elif re.match(r'^\s*module (\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', line):
|
elif re.match(
|
||||||
|
r'^\s*module (\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]',
|
||||||
|
line,
|
||||||
|
):
|
||||||
# It's a private submodule, such as <__utility/swap.h>.
|
# It's a private submodule, such as <__utility/swap.h>.
|
||||||
pass
|
pass
|
||||||
elif re.match(r'^\s*module (\w+)_fwd\s+[{] private header "__fwd/\1[.]h" [}]', line):
|
elif re.match(
|
||||||
|
r'^\s*module (\w+)_fwd\s+[{] private header "__fwd/\1[.]h" [}]',
|
||||||
|
line,
|
||||||
|
):
|
||||||
# It's a private submodule with forward declarations, such as <__fwd/span.h>.
|
# It's a private submodule with forward declarations, such as <__fwd/span.h>.
|
||||||
pass
|
pass
|
||||||
elif re.match(r'^\s*module (?:\w+_)*(\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', line):
|
elif re.match(
|
||||||
|
r'^\s*module (?:\w+_)*(\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]',
|
||||||
|
line,
|
||||||
|
):
|
||||||
# It's a private pstl submodule, such as <__algorithm/pstl_backends/cpu_backend.h>
|
# It's a private pstl submodule, such as <__algorithm/pstl_backends/cpu_backend.h>
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
okay = False
|
okay = False
|
||||||
print("LINE DOESN'T MATCH REGEX in libcxx/include/module.modulemap.in!")
|
print(
|
||||||
|
"LINE DOESN'T MATCH REGEX in libcxx/include/module.modulemap.in!"
|
||||||
|
)
|
||||||
print(line)
|
print(line)
|
||||||
# Check that these lines are alphabetized.
|
# Check that these lines are alphabetized.
|
||||||
if (prevline is not None) and (line < prevline):
|
if (prevline is not None) and (line < prevline):
|
||||||
okay = False
|
okay = False
|
||||||
print('LINES OUT OF ORDER in libcxx/include/module.modulemap.in!')
|
print("LINES OUT OF ORDER in libcxx/include/module.modulemap.in!")
|
||||||
print(prevline)
|
print(prevline)
|
||||||
print(line)
|
print(line)
|
||||||
prevline = line
|
prevline = line
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
# The tests in this directory need to run Python
|
# The tests in this directory need to run Python
|
||||||
import pipes, sys
|
import pipes, sys
|
||||||
config.substitutions.append(('%{python}', pipes.quote(sys.executable)))
|
|
||||||
|
config.substitutions.append(("%{python}", pipes.quote(sys.executable)))
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Load the same local configuration as the corresponding one in libcxx/test/std
|
# Load the same local configuration as the corresponding one in libcxx/test/std
|
||||||
import os
|
import os
|
||||||
inLibcxx = os.path.join('libcxx', 'test', 'libcxx')
|
|
||||||
inStd = os.path.join('libcxx', 'test', 'std')
|
inLibcxx = os.path.join("libcxx", "test", "libcxx")
|
||||||
|
inStd = os.path.join("libcxx", "test", "std")
|
||||||
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
localConfig = os.path.normpath(os.path.realpath(__file__)).replace(inLibcxx, inStd)
|
||||||
config.load_from_path(localConfig, lit_config)
|
config.load_from_path(localConfig, lit_config)
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
# Add a Lit feature so we can test conditional addition of compile flags.
|
# Add a Lit feature so we can test conditional addition of compile flags.
|
||||||
config.available_features.add('some-defined-feature')
|
config.available_features.add("some-defined-feature")
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
# Note: We prepend arguments with 'x' to avoid thinking there are too few
|
# Note: We prepend arguments with 'x' to avoid thinking there are too few
|
||||||
# arguments in case an argument is an empty string.
|
# arguments in case an argument is an empty string.
|
||||||
@ -23,15 +23,17 @@ from os.path import dirname
|
|||||||
# Allow importing 'lit' and the 'libcxx' module. Make sure we put the lit
|
# Allow importing 'lit' and the 'libcxx' module. Make sure we put the lit
|
||||||
# path first so we don't find any system-installed version.
|
# path first so we don't find any system-installed version.
|
||||||
monorepoRoot = dirname(dirname(dirname(dirname(dirname(dirname(__file__))))))
|
monorepoRoot = dirname(dirname(dirname(dirname(dirname(dirname(__file__))))))
|
||||||
sys.path = [os.path.join(monorepoRoot, 'libcxx', 'utils'),
|
sys.path = [
|
||||||
os.path.join(monorepoRoot, 'llvm', 'utils', 'lit')] + sys.path
|
os.path.join(monorepoRoot, "libcxx", "utils"),
|
||||||
|
os.path.join(monorepoRoot, "llvm", "utils", "lit"),
|
||||||
|
] + sys.path
|
||||||
import libcxx.test.dsl as dsl
|
import libcxx.test.dsl as dsl
|
||||||
import lit.LitConfig
|
import lit.LitConfig
|
||||||
import lit.util
|
import lit.util
|
||||||
|
|
||||||
# Steal some parameters from the config running this test so that we can
|
# Steal some parameters from the config running this test so that we can
|
||||||
# bootstrap our own TestingConfig.
|
# bootstrap our own TestingConfig.
|
||||||
args = list(map(lambda s: s[1:], sys.argv[1:8])) # Remove the leading 'x'
|
args = list(map(lambda s: s[1:], sys.argv[1:8])) # Remove the leading 'x'
|
||||||
SOURCE_ROOT, EXEC_PATH, SUBSTITUTIONS = args
|
SOURCE_ROOT, EXEC_PATH, SUBSTITUTIONS = args
|
||||||
sys.argv[1:8] = []
|
sys.argv[1:8] = []
|
||||||
|
|
||||||
@ -40,10 +42,12 @@ SUBSTITUTIONS = pickle.loads(base64.b64decode(SUBSTITUTIONS))
|
|||||||
for s, sub in SUBSTITUTIONS:
|
for s, sub in SUBSTITUTIONS:
|
||||||
print("Substitution '{}' is '{}'".format(s, sub))
|
print("Substitution '{}' is '{}'".format(s, sub))
|
||||||
|
|
||||||
|
|
||||||
class SetupConfigs(unittest.TestCase):
|
class SetupConfigs(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Base class for the tests below -- it creates a fake TestingConfig.
|
Base class for the tests below -- it creates a fake TestingConfig.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
Create a fake TestingConfig that can be populated however we wish for
|
Create a fake TestingConfig that can be populated however we wish for
|
||||||
@ -51,7 +55,7 @@ class SetupConfigs(unittest.TestCase):
|
|||||||
minimum required substitutions.
|
minimum required substitutions.
|
||||||
"""
|
"""
|
||||||
self.litConfig = lit.LitConfig.LitConfig(
|
self.litConfig = lit.LitConfig.LitConfig(
|
||||||
progname='lit',
|
progname="lit",
|
||||||
path=[],
|
path=[],
|
||||||
quiet=False,
|
quiet=False,
|
||||||
useValgrind=False,
|
useValgrind=False,
|
||||||
@ -59,9 +63,10 @@ class SetupConfigs(unittest.TestCase):
|
|||||||
valgrindArgs=[],
|
valgrindArgs=[],
|
||||||
noExecute=False,
|
noExecute=False,
|
||||||
debug=False,
|
debug=False,
|
||||||
isWindows=platform.system() == 'Windows',
|
isWindows=platform.system() == "Windows",
|
||||||
order='smart',
|
order="smart",
|
||||||
params={})
|
params={},
|
||||||
|
)
|
||||||
|
|
||||||
self.config = lit.TestingConfig.TestingConfig.fromdefaults(self.litConfig)
|
self.config = lit.TestingConfig.TestingConfig.fromdefaults(self.litConfig)
|
||||||
self.config.environment = dict(os.environ)
|
self.config.environment = dict(os.environ)
|
||||||
@ -82,7 +87,7 @@ class SetupConfigs(unittest.TestCase):
|
|||||||
|
|
||||||
def findIndex(list, pred):
|
def findIndex(list, pred):
|
||||||
"""Finds the index of the first element satisfying 'pred' in a list, or
|
"""Finds the index of the first element satisfying 'pred' in a list, or
|
||||||
'len(list)' if there is no such element."""
|
'len(list)' if there is no such element."""
|
||||||
index = 0
|
index = 0
|
||||||
for x in list:
|
for x in list:
|
||||||
if pred(x):
|
if pred(x):
|
||||||
@ -96,23 +101,27 @@ class TestHasCompileFlag(SetupConfigs):
|
|||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.hasCompileFlag
|
Tests for libcxx.test.dsl.hasCompileFlag
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_no_flag_should_work(self):
|
def test_no_flag_should_work(self):
|
||||||
self.assertTrue(dsl.hasCompileFlag(self.config, ''))
|
self.assertTrue(dsl.hasCompileFlag(self.config, ""))
|
||||||
|
|
||||||
def test_flag_exists(self):
|
def test_flag_exists(self):
|
||||||
self.assertTrue(dsl.hasCompileFlag(self.config, '-O1'))
|
self.assertTrue(dsl.hasCompileFlag(self.config, "-O1"))
|
||||||
|
|
||||||
def test_nonexistent_flag(self):
|
def test_nonexistent_flag(self):
|
||||||
self.assertFalse(dsl.hasCompileFlag(self.config, '-this_is_not_a_flag_any_compiler_has'))
|
self.assertFalse(
|
||||||
|
dsl.hasCompileFlag(self.config, "-this_is_not_a_flag_any_compiler_has")
|
||||||
|
)
|
||||||
|
|
||||||
def test_multiple_flags(self):
|
def test_multiple_flags(self):
|
||||||
self.assertTrue(dsl.hasCompileFlag(self.config, '-O1 -Dhello'))
|
self.assertTrue(dsl.hasCompileFlag(self.config, "-O1 -Dhello"))
|
||||||
|
|
||||||
|
|
||||||
class TestSourceBuilds(SetupConfigs):
|
class TestSourceBuilds(SetupConfigs):
|
||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.sourceBuilds
|
Tests for libcxx.test.dsl.sourceBuilds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_valid_program_builds(self):
|
def test_valid_program_builds(self):
|
||||||
source = """int main(int, char**) { return 0; }"""
|
source = """int main(int, char**) { return 0; }"""
|
||||||
self.assertTrue(dsl.sourceBuilds(self.config, source))
|
self.assertTrue(dsl.sourceBuilds(self.config, source))
|
||||||
@ -131,6 +140,7 @@ class TestProgramOutput(SetupConfigs):
|
|||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.programOutput
|
Tests for libcxx.test.dsl.programOutput
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_valid_program_returns_output(self):
|
def test_valid_program_returns_output(self):
|
||||||
source = """
|
source = """
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -156,14 +166,20 @@ class TestProgramOutput(SetupConfigs):
|
|||||||
source = """
|
source = """
|
||||||
int main(int, char**) { return 1; }
|
int main(int, char**) { return 1; }
|
||||||
"""
|
"""
|
||||||
self.assertRaises(dsl.ConfigurationRuntimeError, lambda: dsl.programOutput(self.config, source))
|
self.assertRaises(
|
||||||
|
dsl.ConfigurationRuntimeError,
|
||||||
|
lambda: dsl.programOutput(self.config, source),
|
||||||
|
)
|
||||||
|
|
||||||
def test_program_that_fails_to_compile_raises_compilation_error(self):
|
def test_program_that_fails_to_compile_raises_compilation_error(self):
|
||||||
# The program doesn't compile
|
# The program doesn't compile
|
||||||
source = """
|
source = """
|
||||||
int main(int, char**) { this doesnt compile }
|
int main(int, char**) { this doesnt compile }
|
||||||
"""
|
"""
|
||||||
self.assertRaises(dsl.ConfigurationCompilationError, lambda: dsl.programOutput(self.config, source))
|
self.assertRaises(
|
||||||
|
dsl.ConfigurationCompilationError,
|
||||||
|
lambda: dsl.programOutput(self.config, source),
|
||||||
|
)
|
||||||
|
|
||||||
def test_pass_arguments_to_program(self):
|
def test_pass_arguments_to_program(self):
|
||||||
source = """
|
source = """
|
||||||
@ -191,14 +207,22 @@ class TestProgramOutput(SetupConfigs):
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
compileFlagsIndex = findIndex(self.config.substitutions, lambda x: x[0] == '%{compile_flags}')
|
compileFlagsIndex = findIndex(
|
||||||
|
self.config.substitutions, lambda x: x[0] == "%{compile_flags}"
|
||||||
|
)
|
||||||
compileFlags = self.config.substitutions[compileFlagsIndex][1]
|
compileFlags = self.config.substitutions[compileFlagsIndex][1]
|
||||||
|
|
||||||
self.config.substitutions[compileFlagsIndex] = ('%{compile_flags}', compileFlags + ' -DMACRO=1')
|
self.config.substitutions[compileFlagsIndex] = (
|
||||||
|
"%{compile_flags}",
|
||||||
|
compileFlags + " -DMACRO=1",
|
||||||
|
)
|
||||||
output1 = dsl.programOutput(self.config, source)
|
output1 = dsl.programOutput(self.config, source)
|
||||||
self.assertEqual(output1, "MACRO=1\n")
|
self.assertEqual(output1, "MACRO=1\n")
|
||||||
|
|
||||||
self.config.substitutions[compileFlagsIndex] = ('%{compile_flags}', compileFlags + ' -DMACRO=2')
|
self.config.substitutions[compileFlagsIndex] = (
|
||||||
|
"%{compile_flags}",
|
||||||
|
compileFlags + " -DMACRO=2",
|
||||||
|
)
|
||||||
output2 = dsl.programOutput(self.config, source)
|
output2 = dsl.programOutput(self.config, source)
|
||||||
self.assertEqual(output2, "MACRO=2\n")
|
self.assertEqual(output2, "MACRO=2\n")
|
||||||
|
|
||||||
@ -220,6 +244,7 @@ class TestProgramSucceeds(SetupConfigs):
|
|||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.programSucceeds
|
Tests for libcxx.test.dsl.programSucceeds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_success(self):
|
def test_success(self):
|
||||||
source = """
|
source = """
|
||||||
int main(int, char**) { return 0; }
|
int main(int, char**) { return 0; }
|
||||||
@ -236,33 +261,47 @@ class TestProgramSucceeds(SetupConfigs):
|
|||||||
source = """
|
source = """
|
||||||
this does not compile
|
this does not compile
|
||||||
"""
|
"""
|
||||||
self.assertRaises(dsl.ConfigurationCompilationError, lambda: dsl.programSucceeds(self.config, source))
|
self.assertRaises(
|
||||||
|
dsl.ConfigurationCompilationError,
|
||||||
|
lambda: dsl.programSucceeds(self.config, source),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestHasLocale(SetupConfigs):
|
class TestHasLocale(SetupConfigs):
|
||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.hasLocale
|
Tests for libcxx.test.dsl.hasLocale
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_doesnt_explode(self):
|
def test_doesnt_explode(self):
|
||||||
# It's really hard to test that a system has a given locale, so at least
|
# It's really hard to test that a system has a given locale, so at least
|
||||||
# make sure we don't explode when we try to check it.
|
# make sure we don't explode when we try to check it.
|
||||||
try:
|
try:
|
||||||
dsl.hasAnyLocale(self.config, ['en_US.UTF-8'])
|
dsl.hasAnyLocale(self.config, ["en_US.UTF-8"])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
self.fail("checking for hasLocale should not explode")
|
self.fail("checking for hasLocale should not explode")
|
||||||
|
|
||||||
def test_nonexistent_locale(self):
|
def test_nonexistent_locale(self):
|
||||||
self.assertFalse(dsl.hasAnyLocale(self.config, ['forsurethisisnotanexistinglocale']))
|
self.assertFalse(
|
||||||
|
dsl.hasAnyLocale(self.config, ["forsurethisisnotanexistinglocale"])
|
||||||
|
)
|
||||||
|
|
||||||
def test_localization_program_doesnt_compile(self):
|
def test_localization_program_doesnt_compile(self):
|
||||||
compilerIndex = findIndex(self.config.substitutions, lambda x: x[0] == '%{cxx}')
|
compilerIndex = findIndex(self.config.substitutions, lambda x: x[0] == "%{cxx}")
|
||||||
self.config.substitutions[compilerIndex] = ('%{cxx}', 'this-is-certainly-not-a-valid-compiler!!')
|
self.config.substitutions[compilerIndex] = (
|
||||||
self.assertRaises(dsl.ConfigurationCompilationError, lambda: dsl.hasAnyLocale(self.config, ['en_US.UTF-8']))
|
"%{cxx}",
|
||||||
|
"this-is-certainly-not-a-valid-compiler!!",
|
||||||
|
)
|
||||||
|
self.assertRaises(
|
||||||
|
dsl.ConfigurationCompilationError,
|
||||||
|
lambda: dsl.hasAnyLocale(self.config, ["en_US.UTF-8"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestCompilerMacros(SetupConfigs):
|
class TestCompilerMacros(SetupConfigs):
|
||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.compilerMacros
|
Tests for libcxx.test.dsl.compilerMacros
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
macros = dsl.compilerMacros(self.config)
|
macros = dsl.compilerMacros(self.config)
|
||||||
self.assertIsInstance(macros, dict)
|
self.assertIsInstance(macros, dict)
|
||||||
@ -273,28 +312,29 @@ class TestCompilerMacros(SetupConfigs):
|
|||||||
|
|
||||||
def test_no_flag(self):
|
def test_no_flag(self):
|
||||||
macros = dsl.compilerMacros(self.config)
|
macros = dsl.compilerMacros(self.config)
|
||||||
self.assertIn('__cplusplus', macros.keys())
|
self.assertIn("__cplusplus", macros.keys())
|
||||||
|
|
||||||
def test_empty_flag(self):
|
def test_empty_flag(self):
|
||||||
macros = dsl.compilerMacros(self.config, '')
|
macros = dsl.compilerMacros(self.config, "")
|
||||||
self.assertIn('__cplusplus', macros.keys())
|
self.assertIn("__cplusplus", macros.keys())
|
||||||
|
|
||||||
def test_with_flag(self):
|
def test_with_flag(self):
|
||||||
macros = dsl.compilerMacros(self.config, '-DFOO=3')
|
macros = dsl.compilerMacros(self.config, "-DFOO=3")
|
||||||
self.assertIn('__cplusplus', macros.keys())
|
self.assertIn("__cplusplus", macros.keys())
|
||||||
self.assertEqual(macros['FOO'], '3')
|
self.assertEqual(macros["FOO"], "3")
|
||||||
|
|
||||||
def test_with_flags(self):
|
def test_with_flags(self):
|
||||||
macros = dsl.compilerMacros(self.config, '-DFOO=3 -DBAR=hello')
|
macros = dsl.compilerMacros(self.config, "-DFOO=3 -DBAR=hello")
|
||||||
self.assertIn('__cplusplus', macros.keys())
|
self.assertIn("__cplusplus", macros.keys())
|
||||||
self.assertEqual(macros['FOO'], '3')
|
self.assertEqual(macros["FOO"], "3")
|
||||||
self.assertEqual(macros['BAR'], 'hello')
|
self.assertEqual(macros["BAR"], "hello")
|
||||||
|
|
||||||
|
|
||||||
class TestFeatureTestMacros(SetupConfigs):
|
class TestFeatureTestMacros(SetupConfigs):
|
||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.featureTestMacros
|
Tests for libcxx.test.dsl.featureTestMacros
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
macros = dsl.featureTestMacros(self.config)
|
macros = dsl.featureTestMacros(self.config)
|
||||||
self.assertIsInstance(macros, dict)
|
self.assertIsInstance(macros, dict)
|
||||||
@ -308,21 +348,22 @@ class TestFeature(SetupConfigs):
|
|||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.Feature
|
Tests for libcxx.test.dsl.Feature
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_trivial(self):
|
def test_trivial(self):
|
||||||
feature = dsl.Feature(name='name')
|
feature = dsl.Feature(name="name")
|
||||||
origSubstitutions = copy.deepcopy(self.config.substitutions)
|
origSubstitutions = copy.deepcopy(self.config.substitutions)
|
||||||
actions = feature.getActions(self.config)
|
actions = feature.getActions(self.config)
|
||||||
self.assertTrue(len(actions) == 1)
|
self.assertTrue(len(actions) == 1)
|
||||||
for a in actions:
|
for a in actions:
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertEqual(origSubstitutions, self.config.substitutions)
|
self.assertEqual(origSubstitutions, self.config.substitutions)
|
||||||
self.assertIn('name', self.config.available_features)
|
self.assertIn("name", self.config.available_features)
|
||||||
|
|
||||||
def test_name_can_be_a_callable(self):
|
def test_name_can_be_a_callable(self):
|
||||||
feature = dsl.Feature(name=lambda cfg: 'name')
|
feature = dsl.Feature(name=lambda cfg: "name")
|
||||||
for a in feature.getActions(self.config):
|
for a in feature.getActions(self.config):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('name', self.config.available_features)
|
self.assertIn("name", self.config.available_features)
|
||||||
|
|
||||||
def test_name_is_not_a_string_1(self):
|
def test_name_is_not_a_string_1(self):
|
||||||
feature = dsl.Feature(name=None)
|
feature = dsl.Feature(name=None)
|
||||||
@ -335,159 +376,250 @@ class TestFeature(SetupConfigs):
|
|||||||
self.assertRaises(ValueError, lambda: feature.pretty(self.config))
|
self.assertRaises(ValueError, lambda: feature.pretty(self.config))
|
||||||
|
|
||||||
def test_adding_action(self):
|
def test_adding_action(self):
|
||||||
feature = dsl.Feature(name='name', actions=[dsl.AddCompileFlag('-std=c++03')])
|
feature = dsl.Feature(name="name", actions=[dsl.AddCompileFlag("-std=c++03")])
|
||||||
origLinkFlags = copy.deepcopy(self.getSubstitution('%{link_flags}'))
|
origLinkFlags = copy.deepcopy(self.getSubstitution("%{link_flags}"))
|
||||||
for a in feature.getActions(self.config):
|
for a in feature.getActions(self.config):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('name', self.config.available_features)
|
self.assertIn("name", self.config.available_features)
|
||||||
self.assertIn('-std=c++03', self.getSubstitution('%{compile_flags}'))
|
self.assertIn("-std=c++03", self.getSubstitution("%{compile_flags}"))
|
||||||
self.assertEqual(origLinkFlags, self.getSubstitution('%{link_flags}'))
|
self.assertEqual(origLinkFlags, self.getSubstitution("%{link_flags}"))
|
||||||
|
|
||||||
def test_actions_can_be_a_callable(self):
|
def test_actions_can_be_a_callable(self):
|
||||||
feature = dsl.Feature(name='name',
|
feature = dsl.Feature(
|
||||||
actions=lambda cfg: (
|
name="name",
|
||||||
self.assertIs(self.config, cfg),
|
actions=lambda cfg: (
|
||||||
[dsl.AddCompileFlag('-std=c++03')]
|
self.assertIs(self.config, cfg),
|
||||||
)[1])
|
[dsl.AddCompileFlag("-std=c++03")],
|
||||||
|
)[1],
|
||||||
|
)
|
||||||
for a in feature.getActions(self.config):
|
for a in feature.getActions(self.config):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('-std=c++03', self.getSubstitution('%{compile_flags}'))
|
self.assertIn("-std=c++03", self.getSubstitution("%{compile_flags}"))
|
||||||
|
|
||||||
def test_unsupported_feature(self):
|
def test_unsupported_feature(self):
|
||||||
feature = dsl.Feature(name='name', when=lambda _: False)
|
feature = dsl.Feature(name="name", when=lambda _: False)
|
||||||
self.assertEqual(feature.getActions(self.config), [])
|
self.assertEqual(feature.getActions(self.config), [])
|
||||||
|
|
||||||
def test_is_supported_gets_passed_the_config(self):
|
def test_is_supported_gets_passed_the_config(self):
|
||||||
feature = dsl.Feature(name='name', when=lambda cfg: (self.assertIs(self.config, cfg), True)[1])
|
feature = dsl.Feature(
|
||||||
|
name="name", when=lambda cfg: (self.assertIs(self.config, cfg), True)[1]
|
||||||
|
)
|
||||||
self.assertEqual(len(feature.getActions(self.config)), 1)
|
self.assertEqual(len(feature.getActions(self.config)), 1)
|
||||||
|
|
||||||
|
|
||||||
def _throw():
|
def _throw():
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
class TestParameter(SetupConfigs):
|
class TestParameter(SetupConfigs):
|
||||||
"""
|
"""
|
||||||
Tests for libcxx.test.dsl.Parameter
|
Tests for libcxx.test.dsl.Parameter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_empty_name_should_blow_up(self):
|
def test_empty_name_should_blow_up(self):
|
||||||
self.assertRaises(ValueError, lambda: dsl.Parameter(name='', choices=['c++03'], type=str, help='', actions=lambda _: []))
|
self.assertRaises(
|
||||||
|
ValueError,
|
||||||
|
lambda: dsl.Parameter(
|
||||||
|
name="", choices=["c++03"], type=str, help="", actions=lambda _: []
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_empty_choices_should_blow_up(self):
|
def test_empty_choices_should_blow_up(self):
|
||||||
self.assertRaises(ValueError, lambda: dsl.Parameter(name='std', choices=[], type=str, help='', actions=lambda _: []))
|
self.assertRaises(
|
||||||
|
ValueError,
|
||||||
|
lambda: dsl.Parameter(
|
||||||
|
name="std", choices=[], type=str, help="", actions=lambda _: []
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def test_no_choices_is_ok(self):
|
def test_no_choices_is_ok(self):
|
||||||
param = dsl.Parameter(name='triple', type=str, help='', actions=lambda _: [])
|
param = dsl.Parameter(name="triple", type=str, help="", actions=lambda _: [])
|
||||||
self.assertEqual(param.name, 'triple')
|
self.assertEqual(param.name, "triple")
|
||||||
|
|
||||||
def test_name_is_set_correctly(self):
|
def test_name_is_set_correctly(self):
|
||||||
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', actions=lambda _: [])
|
param = dsl.Parameter(
|
||||||
self.assertEqual(param.name, 'std')
|
name="std", choices=["c++03"], type=str, help="", actions=lambda _: []
|
||||||
|
)
|
||||||
|
self.assertEqual(param.name, "std")
|
||||||
|
|
||||||
def test_no_value_provided_and_no_default_value(self):
|
def test_no_value_provided_and_no_default_value(self):
|
||||||
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', actions=lambda _: [])
|
param = dsl.Parameter(
|
||||||
self.assertRaises(ValueError, lambda: param.getActions(self.config, self.litConfig.params))
|
name="std", choices=["c++03"], type=str, help="", actions=lambda _: []
|
||||||
|
)
|
||||||
|
self.assertRaises(
|
||||||
|
ValueError, lambda: param.getActions(self.config, self.litConfig.params)
|
||||||
|
)
|
||||||
|
|
||||||
def test_no_value_provided_and_default_value(self):
|
def test_no_value_provided_and_default_value(self):
|
||||||
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', default='c++03',
|
param = dsl.Parameter(
|
||||||
actions=lambda std: [dsl.AddFeature(std)])
|
name="std",
|
||||||
|
choices=["c++03"],
|
||||||
|
type=str,
|
||||||
|
help="",
|
||||||
|
default="c++03",
|
||||||
|
actions=lambda std: [dsl.AddFeature(std)],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('c++03', self.config.available_features)
|
self.assertIn("c++03", self.config.available_features)
|
||||||
|
|
||||||
def test_value_provided_on_command_line_and_no_default_value(self):
|
def test_value_provided_on_command_line_and_no_default_value(self):
|
||||||
self.litConfig.params['std'] = 'c++03'
|
self.litConfig.params["std"] = "c++03"
|
||||||
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda std: [dsl.AddFeature(std)])
|
name="std",
|
||||||
|
choices=["c++03"],
|
||||||
|
type=str,
|
||||||
|
help="",
|
||||||
|
actions=lambda std: [dsl.AddFeature(std)],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('c++03', self.config.available_features)
|
self.assertIn("c++03", self.config.available_features)
|
||||||
|
|
||||||
def test_value_provided_on_command_line_and_default_value(self):
|
def test_value_provided_on_command_line_and_default_value(self):
|
||||||
"""The value provided on the command line should override the default value"""
|
"""The value provided on the command line should override the default value"""
|
||||||
self.litConfig.params['std'] = 'c++11'
|
self.litConfig.params["std"] = "c++11"
|
||||||
param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, default='c++03', help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda std: [dsl.AddFeature(std)])
|
name="std",
|
||||||
|
choices=["c++03", "c++11"],
|
||||||
|
type=str,
|
||||||
|
default="c++03",
|
||||||
|
help="",
|
||||||
|
actions=lambda std: [dsl.AddFeature(std)],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('c++11', self.config.available_features)
|
self.assertIn("c++11", self.config.available_features)
|
||||||
self.assertNotIn('c++03', self.config.available_features)
|
self.assertNotIn("c++03", self.config.available_features)
|
||||||
|
|
||||||
def test_value_provided_in_config_and_default_value(self):
|
def test_value_provided_in_config_and_default_value(self):
|
||||||
"""The value provided in the config should override the default value"""
|
"""The value provided in the config should override the default value"""
|
||||||
self.config.std ='c++11'
|
self.config.std = "c++11"
|
||||||
param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, default='c++03', help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda std: [dsl.AddFeature(std)])
|
name="std",
|
||||||
|
choices=["c++03", "c++11"],
|
||||||
|
type=str,
|
||||||
|
default="c++03",
|
||||||
|
help="",
|
||||||
|
actions=lambda std: [dsl.AddFeature(std)],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('c++11', self.config.available_features)
|
self.assertIn("c++11", self.config.available_features)
|
||||||
self.assertNotIn('c++03', self.config.available_features)
|
self.assertNotIn("c++03", self.config.available_features)
|
||||||
|
|
||||||
def test_value_provided_in_config_and_on_command_line(self):
|
def test_value_provided_in_config_and_on_command_line(self):
|
||||||
"""The value on the command line should override the one in the config"""
|
"""The value on the command line should override the one in the config"""
|
||||||
self.config.std = 'c++11'
|
self.config.std = "c++11"
|
||||||
self.litConfig.params['std'] = 'c++03'
|
self.litConfig.params["std"] = "c++03"
|
||||||
param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda std: [dsl.AddFeature(std)])
|
name="std",
|
||||||
|
choices=["c++03", "c++11"],
|
||||||
|
type=str,
|
||||||
|
help="",
|
||||||
|
actions=lambda std: [dsl.AddFeature(std)],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('c++03', self.config.available_features)
|
self.assertIn("c++03", self.config.available_features)
|
||||||
self.assertNotIn('c++11', self.config.available_features)
|
self.assertNotIn("c++11", self.config.available_features)
|
||||||
|
|
||||||
def test_no_actions(self):
|
def test_no_actions(self):
|
||||||
self.litConfig.params['std'] = 'c++03'
|
self.litConfig.params["std"] = "c++03"
|
||||||
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda _: [])
|
name="std", choices=["c++03"], type=str, help="", actions=lambda _: []
|
||||||
|
)
|
||||||
actions = param.getActions(self.config, self.litConfig.params)
|
actions = param.getActions(self.config, self.litConfig.params)
|
||||||
self.assertEqual(actions, [])
|
self.assertEqual(actions, [])
|
||||||
|
|
||||||
def test_boolean_value_parsed_from_trueish_string_parameter(self):
|
def test_boolean_value_parsed_from_trueish_string_parameter(self):
|
||||||
self.litConfig.params['enable_exceptions'] = "True"
|
self.litConfig.params["enable_exceptions"] = "True"
|
||||||
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda exceptions: [] if exceptions else _throw())
|
name="enable_exceptions",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
help="",
|
||||||
|
actions=lambda exceptions: [] if exceptions else _throw(),
|
||||||
|
)
|
||||||
self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
|
self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
|
||||||
|
|
||||||
def test_boolean_value_from_true_boolean_parameter(self):
|
def test_boolean_value_from_true_boolean_parameter(self):
|
||||||
self.litConfig.params['enable_exceptions'] = True
|
self.litConfig.params["enable_exceptions"] = True
|
||||||
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda exceptions: [] if exceptions else _throw())
|
name="enable_exceptions",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
help="",
|
||||||
|
actions=lambda exceptions: [] if exceptions else _throw(),
|
||||||
|
)
|
||||||
self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
|
self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
|
||||||
|
|
||||||
def test_boolean_value_parsed_from_falseish_string_parameter(self):
|
def test_boolean_value_parsed_from_falseish_string_parameter(self):
|
||||||
self.litConfig.params['enable_exceptions'] = "False"
|
self.litConfig.params["enable_exceptions"] = "False"
|
||||||
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda exceptions: [] if exceptions else [dsl.AddFeature("-fno-exceptions")])
|
name="enable_exceptions",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
help="",
|
||||||
|
actions=lambda exceptions: []
|
||||||
|
if exceptions
|
||||||
|
else [dsl.AddFeature("-fno-exceptions")],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('-fno-exceptions', self.config.available_features)
|
self.assertIn("-fno-exceptions", self.config.available_features)
|
||||||
|
|
||||||
def test_boolean_value_from_false_boolean_parameter(self):
|
def test_boolean_value_from_false_boolean_parameter(self):
|
||||||
self.litConfig.params['enable_exceptions'] = False
|
self.litConfig.params["enable_exceptions"] = False
|
||||||
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
|
param = dsl.Parameter(
|
||||||
actions=lambda exceptions: [] if exceptions else [dsl.AddFeature("-fno-exceptions")])
|
name="enable_exceptions",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
help="",
|
||||||
|
actions=lambda exceptions: []
|
||||||
|
if exceptions
|
||||||
|
else [dsl.AddFeature("-fno-exceptions")],
|
||||||
|
)
|
||||||
for a in param.getActions(self.config, self.litConfig.params):
|
for a in param.getActions(self.config, self.litConfig.params):
|
||||||
a.applyTo(self.config)
|
a.applyTo(self.config)
|
||||||
self.assertIn('-fno-exceptions', self.config.available_features)
|
self.assertIn("-fno-exceptions", self.config.available_features)
|
||||||
|
|
||||||
def test_list_parsed_from_comma_delimited_string_empty(self):
|
def test_list_parsed_from_comma_delimited_string_empty(self):
|
||||||
self.litConfig.params['additional_features'] = ""
|
self.litConfig.params["additional_features"] = ""
|
||||||
param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f)
|
param = dsl.Parameter(
|
||||||
|
name="additional_features", type=list, help="", actions=lambda f: f
|
||||||
|
)
|
||||||
self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
|
self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
|
||||||
|
|
||||||
def test_list_parsed_from_comma_delimited_string_1(self):
|
def test_list_parsed_from_comma_delimited_string_1(self):
|
||||||
self.litConfig.params['additional_features'] = "feature1"
|
self.litConfig.params["additional_features"] = "feature1"
|
||||||
param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f)
|
param = dsl.Parameter(
|
||||||
self.assertEqual(param.getActions(self.config, self.litConfig.params), ['feature1'])
|
name="additional_features", type=list, help="", actions=lambda f: f
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
param.getActions(self.config, self.litConfig.params), ["feature1"]
|
||||||
|
)
|
||||||
|
|
||||||
def test_list_parsed_from_comma_delimited_string_2(self):
|
def test_list_parsed_from_comma_delimited_string_2(self):
|
||||||
self.litConfig.params['additional_features'] = "feature1,feature2"
|
self.litConfig.params["additional_features"] = "feature1,feature2"
|
||||||
param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f)
|
param = dsl.Parameter(
|
||||||
self.assertEqual(param.getActions(self.config, self.litConfig.params), ['feature1', 'feature2'])
|
name="additional_features", type=list, help="", actions=lambda f: f
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
param.getActions(self.config, self.litConfig.params),
|
||||||
|
["feature1", "feature2"],
|
||||||
|
)
|
||||||
|
|
||||||
def test_list_parsed_from_comma_delimited_string_3(self):
|
def test_list_parsed_from_comma_delimited_string_3(self):
|
||||||
self.litConfig.params['additional_features'] = "feature1,feature2, feature3"
|
self.litConfig.params["additional_features"] = "feature1,feature2, feature3"
|
||||||
param = dsl.Parameter(name='additional_features', type=list, help='', actions=lambda f: f)
|
param = dsl.Parameter(
|
||||||
self.assertEqual(param.getActions(self.config, self.litConfig.params), ['feature1', 'feature2', 'feature3'])
|
name="additional_features", type=list, help="", actions=lambda f: f
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
param.getActions(self.config, self.litConfig.params),
|
||||||
|
["feature1", "feature2", "feature3"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main(verbosity=2)
|
unittest.main(verbosity=2)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
# to pass it to the test, and we decode and unpickle the substitutions from
|
# to pass it to the test, and we decode and unpickle the substitutions from
|
||||||
# within the test.
|
# within the test.
|
||||||
import base64, lit.util, pickle
|
import base64, lit.util, pickle
|
||||||
|
|
||||||
base64Encode = lambda s: lit.util.to_string(base64.b64encode(lit.util.to_bytes(s)))
|
base64Encode = lambda s: lit.util.to_string(base64.b64encode(lit.util.to_bytes(s)))
|
||||||
escapedSubstitutions = base64Encode(pickle.dumps(config.substitutions))
|
escapedSubstitutions = base64Encode(pickle.dumps(config.substitutions))
|
||||||
config.substitutions.append(('%{substitutions}', escapedSubstitutions))
|
config.substitutions.append(("%{substitutions}", escapedSubstitutions))
|
||||||
|
@ -41,7 +41,8 @@ def parse_line(line: str) -> header:
|
|||||||
# literal level.)
|
# literal level.)
|
||||||
LIBCXX_HEADER_REGEX = r".*c\+\+(?:/|\\\\)v[0-9]+(?:/|\\\\)(.+)"
|
LIBCXX_HEADER_REGEX = r".*c\+\+(?:/|\\\\)v[0-9]+(?:/|\\\\)(.+)"
|
||||||
|
|
||||||
def is_libcxx_public_header(header : str) -> bool:
|
|
||||||
|
def is_libcxx_public_header(header: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Returns whether a header is a C++ public header file.
|
Returns whether a header is a C++ public header file.
|
||||||
"""
|
"""
|
||||||
@ -62,7 +63,7 @@ def is_libcxx_public_header(header : str) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def is_libcxx_header(header : str) -> bool:
|
def is_libcxx_header(header: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Returns whether a header is a libc++ header, excluding the C-compatibility headers.
|
Returns whether a header is a libc++ header, excluding the C-compatibility headers.
|
||||||
"""
|
"""
|
||||||
@ -73,7 +74,9 @@ def is_libcxx_header(header : str) -> bool:
|
|||||||
|
|
||||||
# Skip C compatibility headers (in particular, make sure not to skip libc++ detail headers).
|
# Skip C compatibility headers (in particular, make sure not to skip libc++ detail headers).
|
||||||
relative = match.group(1)
|
relative = match.group(1)
|
||||||
if relative.endswith(".h") and not (relative.startswith("__") or re.search(r"(/|\\\\)__", relative)):
|
if relative.endswith(".h") and not (
|
||||||
|
relative.startswith("__") or re.search(r"(/|\\\\)__", relative)
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@ -130,7 +133,9 @@ def create_include_graph(path: pathlib.Path) -> List[str]:
|
|||||||
# Get actual filenames relative to libc++'s installation directory instead of full paths
|
# Get actual filenames relative to libc++'s installation directory instead of full paths
|
||||||
relative = lambda h: re.match(LIBCXX_HEADER_REGEX, h).group(1)
|
relative = lambda h: re.match(LIBCXX_HEADER_REGEX, h).group(1)
|
||||||
|
|
||||||
top_level = relative(next(h.name for h in headers if h.level == 1)) # There should be only one top-level header
|
top_level = relative(
|
||||||
|
next(h.name for h in headers if h.level == 1)
|
||||||
|
) # There should be only one top-level header
|
||||||
includes = [relative(h.name) for h in headers if h.level != 1]
|
includes = [relative(h.name) for h in headers if h.level != 1]
|
||||||
|
|
||||||
# Remove duplicates in all includes.
|
# Remove duplicates in all includes.
|
||||||
|
@ -7,4 +7,5 @@
|
|||||||
lit_config.fatal(
|
lit_config.fatal(
|
||||||
"You seem to be running Lit directly -- you should be running Lit through "
|
"You seem to be running Lit directly -- you should be running Lit through "
|
||||||
"<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
|
"<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
|
||||||
"file is used.")
|
"file is used."
|
||||||
|
)
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# Disable all of the experimental tests if the correct feature is not available.
|
# Disable all of the experimental tests if the correct feature is not available.
|
||||||
if 'c++experimental' not in config.available_features:
|
if "c++experimental" not in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
|
||||||
if 'no-fstream' in config.available_features:
|
if "no-fstream" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
if 'availability-filesystem-missing' in config.available_features:
|
if "availability-filesystem-missing" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
|
||||||
if 'no-filesystem' in config.available_features:
|
if "no-filesystem" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# All non-trivial uses of iostreams require localization support
|
# All non-trivial uses of iostreams require localization support
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# stream iterators rely on the streams library, which requires localization
|
# stream iterators rely on the streams library, which requires localization
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# <locale> tests are obviously not supported when localization support is disabled
|
# <locale> tests are obviously not supported when localization support is disabled
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# Unfortunately, <regex> uses locales in regex_traits
|
# Unfortunately, <regex> uses locales in regex_traits
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# These std::string functions require iostreams, which requires localization
|
# These std::string functions require iostreams, which requires localization
|
||||||
if 'no-localization' in config.available_features:
|
if "no-localization" in config.available_features:
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -1,45 +1,51 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def print_and_exit(msg):
|
def print_and_exit(msg):
|
||||||
sys.stderr.write(msg + '\n')
|
sys.stderr.write(msg + "\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = ArgumentParser(
|
parser = ArgumentParser(description="Concatenate two files into a single file")
|
||||||
description="Concatenate two files into a single file")
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-o', '--output', dest='output', required=True,
|
"-o",
|
||||||
help='The output file. stdout is used if not given',
|
"--output",
|
||||||
type=str, action='store')
|
dest="output",
|
||||||
|
required=True,
|
||||||
|
help="The output file. stdout is used if not given",
|
||||||
|
type=str,
|
||||||
|
action="store",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'files', metavar='files', nargs='+',
|
"files", metavar="files", nargs="+", help="The files to concatenate"
|
||||||
help='The files to concatenate')
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if len(args.files) < 2:
|
if len(args.files) < 2:
|
||||||
print_and_exit('fewer than 2 inputs provided')
|
print_and_exit("fewer than 2 inputs provided")
|
||||||
data = ''
|
data = ""
|
||||||
for filename in args.files:
|
for filename in args.files:
|
||||||
with open(filename, 'r') as f:
|
with open(filename, "r") as f:
|
||||||
data += f.read()
|
data += f.read()
|
||||||
if len(data) != 0 and data[-1] != '\n':
|
if len(data) != 0 and data[-1] != "\n":
|
||||||
data += '\n'
|
data += "\n"
|
||||||
assert len(data) > 0 and "cannot cat empty files"
|
assert len(data) > 0 and "cannot cat empty files"
|
||||||
with open(args.output, 'w') as f:
|
with open(args.output, "w") as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
"""GDB pretty-printers for libc++.
|
"""GDB pretty-printers for libc++.
|
||||||
|
|
||||||
These should work for objects compiled with either the stable ABI or the unstable ABI.
|
These should work for objects compiled with either the stable ABI or the unstable ABI.
|
||||||
@ -29,6 +29,7 @@ _long_int_type = gdb.lookup_type("unsigned long long")
|
|||||||
|
|
||||||
_libcpp_big_endian = False
|
_libcpp_big_endian = False
|
||||||
|
|
||||||
|
|
||||||
def addr_as_long(addr):
|
def addr_as_long(addr):
|
||||||
return int(addr.cast(_long_int_type))
|
return int(addr.cast(_long_int_type))
|
||||||
|
|
||||||
@ -97,10 +98,11 @@ def _size_field(node):
|
|||||||
# Some common substitutions on the types to reduce visual clutter (A user who
|
# Some common substitutions on the types to reduce visual clutter (A user who
|
||||||
# wants to see the actual details can always use print/r).
|
# wants to see the actual details can always use print/r).
|
||||||
_common_substitutions = [
|
_common_substitutions = [
|
||||||
("std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
|
(
|
||||||
"std::string"),
|
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
|
||||||
("std::basic_string_view<char, std::char_traits<char> >",
|
"std::string",
|
||||||
"std::string_view"),
|
),
|
||||||
|
("std::basic_string_view<char, std::char_traits<char> >", "std::string_view"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -116,8 +118,11 @@ def _prettify_typename(gdb_type):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
type_without_typedefs = gdb_type.strip_typedefs()
|
type_without_typedefs = gdb_type.strip_typedefs()
|
||||||
typename = type_without_typedefs.name or type_without_typedefs.tag or \
|
typename = (
|
||||||
str(type_without_typedefs)
|
type_without_typedefs.name
|
||||||
|
or type_without_typedefs.tag
|
||||||
|
or str(type_without_typedefs)
|
||||||
|
)
|
||||||
result = _remove_cxx_namespace(typename)
|
result = _remove_cxx_namespace(typename)
|
||||||
for find_str, subst_str in _common_substitutions:
|
for find_str, subst_str in _common_substitutions:
|
||||||
result = re.sub(find_str, subst_str, result)
|
result = re.sub(find_str, subst_str, result)
|
||||||
@ -247,18 +252,18 @@ class StdStringViewPrinter(object):
|
|||||||
"""Print a std::string_view."""
|
"""Print a std::string_view."""
|
||||||
|
|
||||||
def __init__(self, val):
|
def __init__(self, val):
|
||||||
self.val = val
|
self.val = val
|
||||||
|
|
||||||
def display_hint(self):
|
def display_hint(self):
|
||||||
return "string"
|
return "string"
|
||||||
|
|
||||||
def to_string(self): # pylint: disable=g-bad-name
|
def to_string(self): # pylint: disable=g-bad-name
|
||||||
"""GDB calls this to compute the pretty-printed form."""
|
"""GDB calls this to compute the pretty-printed form."""
|
||||||
|
|
||||||
ptr = _data_field(self.val)
|
ptr = _data_field(self.val)
|
||||||
ptr = ptr.cast(ptr.type.target().strip_typedefs().pointer())
|
ptr = ptr.cast(ptr.type.target().strip_typedefs().pointer())
|
||||||
size = _size_field(self.val)
|
size = _size_field(self.val)
|
||||||
return ptr.lazy_string(length=size)
|
return ptr.lazy_string(length=size)
|
||||||
|
|
||||||
|
|
||||||
class StdUniquePtrPrinter(object):
|
class StdUniquePtrPrinter(object):
|
||||||
@ -273,9 +278,10 @@ class StdUniquePtrPrinter(object):
|
|||||||
typename = _remove_generics(_prettify_typename(self.val.type))
|
typename = _remove_generics(_prettify_typename(self.val.type))
|
||||||
if not self.addr:
|
if not self.addr:
|
||||||
return "%s is nullptr" % typename
|
return "%s is nullptr" % typename
|
||||||
return ("%s<%s> containing" %
|
return "%s<%s> containing" % (
|
||||||
(typename,
|
typename,
|
||||||
_remove_generics(_prettify_typename(self.pointee_type))))
|
_remove_generics(_prettify_typename(self.pointee_type)),
|
||||||
|
)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
if self.addr:
|
if self.addr:
|
||||||
@ -296,7 +302,8 @@ class StdSharedPointerPrinter(object):
|
|||||||
"""Returns self as a string."""
|
"""Returns self as a string."""
|
||||||
typename = _remove_generics(_prettify_typename(self.val.type))
|
typename = _remove_generics(_prettify_typename(self.val.type))
|
||||||
pointee_type = _remove_generics(
|
pointee_type = _remove_generics(
|
||||||
_prettify_typename(self.val.type.template_argument(0)))
|
_prettify_typename(self.val.type.template_argument(0))
|
||||||
|
)
|
||||||
if not self.addr:
|
if not self.addr:
|
||||||
return "%s is nullptr" % typename
|
return "%s is nullptr" % typename
|
||||||
refcount = self.val["__cntrl_"]
|
refcount = self.val["__cntrl_"]
|
||||||
@ -391,20 +398,24 @@ class StdVectorPrinter(object):
|
|||||||
self.typename += "<bool>"
|
self.typename += "<bool>"
|
||||||
self.length = self.val["__size_"]
|
self.length = self.val["__size_"]
|
||||||
bits_per_word = self.val["__bits_per_word"]
|
bits_per_word = self.val["__bits_per_word"]
|
||||||
self.capacity = _value_of_pair_first(
|
self.capacity = (
|
||||||
self.val["__cap_alloc_"]) * bits_per_word
|
_value_of_pair_first(self.val["__cap_alloc_"]) * bits_per_word
|
||||||
self.iterator = self._VectorBoolIterator(
|
)
|
||||||
begin, self.length, bits_per_word)
|
self.iterator = self._VectorBoolIterator(begin, self.length, bits_per_word)
|
||||||
else:
|
else:
|
||||||
end = self.val["__end_"]
|
end = self.val["__end_"]
|
||||||
self.length = end - begin
|
self.length = end - begin
|
||||||
self.capacity = _get_base_subobject(
|
self.capacity = (
|
||||||
self.val["__end_cap_"])["__value_"] - begin
|
_get_base_subobject(self.val["__end_cap_"])["__value_"] - begin
|
||||||
|
)
|
||||||
self.iterator = self._VectorIterator(begin, end)
|
self.iterator = self._VectorIterator(begin, end)
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
return ("%s of length %d, capacity %d" %
|
return "%s of length %d, capacity %d" % (
|
||||||
(self.typename, self.length, self.capacity))
|
self.typename,
|
||||||
|
self.length,
|
||||||
|
self.capacity,
|
||||||
|
)
|
||||||
|
|
||||||
def children(self):
|
def children(self):
|
||||||
return self.iterator
|
return self.iterator
|
||||||
@ -424,8 +435,9 @@ class StdBitsetPrinter(object):
|
|||||||
if self.n_words == 1:
|
if self.n_words == 1:
|
||||||
self.values = [int(self.val["__first_"])]
|
self.values = [int(self.val["__first_"])]
|
||||||
else:
|
else:
|
||||||
self.values = [int(self.val["__first_"][index])
|
self.values = [
|
||||||
for index in range(self.n_words)]
|
int(self.val["__first_"][index]) for index in range(self.n_words)
|
||||||
|
]
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
typename = _prettify_typename(self.val.type)
|
typename = _prettify_typename(self.val.type)
|
||||||
@ -454,8 +466,7 @@ class StdDequePrinter(object):
|
|||||||
self.start_ptr = self.val["__map_"]["__begin_"]
|
self.start_ptr = self.val["__map_"]["__begin_"]
|
||||||
self.first_block_start_index = int(self.val["__start_"])
|
self.first_block_start_index = int(self.val["__start_"])
|
||||||
self.node_type = self.start_ptr.type
|
self.node_type = self.start_ptr.type
|
||||||
self.block_size = self._calculate_block_size(
|
self.block_size = self._calculate_block_size(val.type.template_argument(0))
|
||||||
val.type.template_argument(0))
|
|
||||||
|
|
||||||
def _calculate_block_size(self, element_type):
|
def _calculate_block_size(self, element_type):
|
||||||
"""Calculates the number of elements in a full block."""
|
"""Calculates the number of elements in a full block."""
|
||||||
@ -473,13 +484,13 @@ class StdDequePrinter(object):
|
|||||||
current_addr = self.start_ptr
|
current_addr = self.start_ptr
|
||||||
start_index = self.first_block_start_index
|
start_index = self.first_block_start_index
|
||||||
while num_emitted < self.size:
|
while num_emitted < self.size:
|
||||||
end_index = min(start_index + self.size -
|
end_index = min(start_index + self.size - num_emitted, self.block_size)
|
||||||
num_emitted, self.block_size)
|
|
||||||
for _, elem in self._bucket_it(current_addr, start_index, end_index):
|
for _, elem in self._bucket_it(current_addr, start_index, end_index):
|
||||||
yield "", elem
|
yield "", elem
|
||||||
num_emitted += end_index - start_index
|
num_emitted += end_index - start_index
|
||||||
current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size) \
|
current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size).cast(
|
||||||
.cast(self.node_type)
|
self.node_type
|
||||||
|
)
|
||||||
start_index = 0
|
start_index = 0
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
@ -507,8 +518,10 @@ class StdListPrinter(object):
|
|||||||
self.size = int(_value_of_pair_first(size_alloc_field))
|
self.size = int(_value_of_pair_first(size_alloc_field))
|
||||||
dummy_node = self.val["__end_"]
|
dummy_node = self.val["__end_"]
|
||||||
self.nodetype = gdb.lookup_type(
|
self.nodetype = gdb.lookup_type(
|
||||||
re.sub("__list_node_base", "__list_node",
|
re.sub(
|
||||||
str(dummy_node.type.strip_typedefs()))).pointer()
|
"__list_node_base", "__list_node", str(dummy_node.type.strip_typedefs())
|
||||||
|
)
|
||||||
|
).pointer()
|
||||||
self.first_node = dummy_node["__next_"]
|
self.first_node = dummy_node["__next_"]
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
@ -685,7 +698,8 @@ class StdMapPrinter(AbstractRBTreePrinter):
|
|||||||
|
|
||||||
def _init_cast_type(self, val_type):
|
def _init_cast_type(self, val_type):
|
||||||
map_it_type = gdb.lookup_type(
|
map_it_type = gdb.lookup_type(
|
||||||
str(val_type.strip_typedefs()) + "::iterator").strip_typedefs()
|
str(val_type.strip_typedefs()) + "::iterator"
|
||||||
|
).strip_typedefs()
|
||||||
tree_it_type = map_it_type.template_argument(0)
|
tree_it_type = map_it_type.template_argument(0)
|
||||||
node_ptr_type = tree_it_type.template_argument(1)
|
node_ptr_type = tree_it_type.template_argument(1)
|
||||||
return node_ptr_type
|
return node_ptr_type
|
||||||
@ -703,7 +717,8 @@ class StdSetPrinter(AbstractRBTreePrinter):
|
|||||||
|
|
||||||
def _init_cast_type(self, val_type):
|
def _init_cast_type(self, val_type):
|
||||||
set_it_type = gdb.lookup_type(
|
set_it_type = gdb.lookup_type(
|
||||||
str(val_type.strip_typedefs()) + "::iterator").strip_typedefs()
|
str(val_type.strip_typedefs()) + "::iterator"
|
||||||
|
).strip_typedefs()
|
||||||
node_ptr_type = set_it_type.template_argument(1)
|
node_ptr_type = set_it_type.template_argument(1)
|
||||||
return node_ptr_type
|
return node_ptr_type
|
||||||
|
|
||||||
@ -730,8 +745,7 @@ class AbstractRBTreeIteratorPrinter(object):
|
|||||||
def _is_valid_node(self):
|
def _is_valid_node(self):
|
||||||
if not self.util.parent(self.addr):
|
if not self.util.parent(self.addr):
|
||||||
return False
|
return False
|
||||||
return self.util.is_left_child(self.addr) or \
|
return self.util.is_left_child(self.addr) or self.util.is_right_child(self.addr)
|
||||||
self.util.is_right_child(self.addr)
|
|
||||||
|
|
||||||
def to_string(self):
|
def to_string(self):
|
||||||
if not self.addr:
|
if not self.addr:
|
||||||
@ -756,8 +770,7 @@ class MapIteratorPrinter(AbstractRBTreeIteratorPrinter):
|
|||||||
"""Print a std::(multi)map iterator."""
|
"""Print a std::(multi)map iterator."""
|
||||||
|
|
||||||
def __init__(self, val):
|
def __init__(self, val):
|
||||||
self._initialize(val["__i_"],
|
self._initialize(val["__i_"], _remove_generics(_prettify_typename(val.type)))
|
||||||
_remove_generics(_prettify_typename(val.type)))
|
|
||||||
|
|
||||||
def _get_node_value(self, node):
|
def _get_node_value(self, node):
|
||||||
return _cc_field(node)
|
return _cc_field(node)
|
||||||
@ -976,10 +989,12 @@ class LibcxxPrettyPrinter(object):
|
|||||||
# Don't attempt types known to be inside libstdcxx.
|
# Don't attempt types known to be inside libstdcxx.
|
||||||
typename = val.type.name or val.type.tag or str(val.type)
|
typename = val.type.name or val.type.tag or str(val.type)
|
||||||
match = re.match("^std::(__.*?)::", typename)
|
match = re.match("^std::(__.*?)::", typename)
|
||||||
if match is not None and match.group(1) in ["__cxx1998",
|
if match is not None and match.group(1) in [
|
||||||
"__debug",
|
"__cxx1998",
|
||||||
"__7",
|
"__debug",
|
||||||
"__g"]:
|
"__7",
|
||||||
|
"__g",
|
||||||
|
]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Handle any using declarations or other typedefs.
|
# Handle any using declarations or other typedefs.
|
||||||
@ -1005,13 +1020,13 @@ def _register_libcxx_printers(event):
|
|||||||
# already generated as part of a larger data structure, and there is
|
# already generated as part of a larger data structure, and there is
|
||||||
# no python api to get the endianness. Mixed-endianness debugging
|
# no python api to get the endianness. Mixed-endianness debugging
|
||||||
# rare enough that this workaround should be adequate.
|
# rare enough that this workaround should be adequate.
|
||||||
_libcpp_big_endian = "big endian" in gdb.execute("show endian",
|
_libcpp_big_endian = "big endian" in gdb.execute("show endian", to_string=True)
|
||||||
to_string=True)
|
|
||||||
|
|
||||||
if not getattr(progspace, _libcxx_printer_name, False):
|
if not getattr(progspace, _libcxx_printer_name, False):
|
||||||
print("Loading libc++ pretty-printers.")
|
print("Loading libc++ pretty-printers.")
|
||||||
gdb.printing.register_pretty_printer(
|
gdb.printing.register_pretty_printer(
|
||||||
progspace, LibcxxPrettyPrinter(_libcxx_printer_name))
|
progspace, LibcxxPrettyPrinter(_libcxx_printer_name)
|
||||||
|
)
|
||||||
setattr(progspace, _libcxx_printer_name, True)
|
setattr(progspace, _libcxx_printer_name, True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import io
|
import io
|
||||||
@ -14,27 +14,38 @@ import libcxx.sym_check.util
|
|||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def OutputFile(file):
|
def OutputFile(file):
|
||||||
if isinstance(file, io.IOBase):
|
if isinstance(file, io.IOBase):
|
||||||
return file
|
return file
|
||||||
assert isinstance(file, str), "Got object {} which is not a str".format(file)
|
assert isinstance(file, str), "Got object {} which is not a str".format(file)
|
||||||
return open(file, 'w', newline='\n')
|
return open(file, "w", newline="\n")
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Extract a list of symbols from a shared library.')
|
description="Extract a list of symbols from a shared library."
|
||||||
parser.add_argument('library', metavar='LIB', type=str,
|
)
|
||||||
help='The library to extract symbols from.')
|
parser.add_argument(
|
||||||
parser.add_argument('-o', '--output', dest='output', type=OutputFile, default=sys.stdout,
|
"library", metavar="LIB", type=str, help="The library to extract symbols from."
|
||||||
help='The output file to write the symbols to. It is overwritten if it already exists. '
|
)
|
||||||
'If no file is specified, the results are written to standard output.')
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--output",
|
||||||
|
dest="output",
|
||||||
|
type=OutputFile,
|
||||||
|
default=sys.stdout,
|
||||||
|
help="The output file to write the symbols to. It is overwritten if it already exists. "
|
||||||
|
"If no file is specified, the results are written to standard output.",
|
||||||
|
)
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
symbols = libcxx.sym_check.extract.extract_symbols(args.library)
|
symbols = libcxx.sym_check.extract.extract_symbols(args.library)
|
||||||
symbols, _ = libcxx.sym_check.util.filter_stdlib_symbols(symbols)
|
symbols, _ = libcxx.sym_check.util.filter_stdlib_symbols(symbols)
|
||||||
|
|
||||||
lines = [pprint.pformat(sym, width=99999) for sym in symbols]
|
lines = [pprint.pformat(sym, width=99999) for sym in symbols]
|
||||||
args.output.writelines('\n'.join(sorted(lines)))
|
args.output.writelines("\n".join(sorted(lines)))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,9 +8,11 @@ def get_libcxx_paths():
|
|||||||
script_name = os.path.basename(__file__)
|
script_name = os.path.basename(__file__)
|
||||||
assert os.path.exists(utils_path)
|
assert os.path.exists(utils_path)
|
||||||
src_root = os.path.dirname(utils_path)
|
src_root = os.path.dirname(utils_path)
|
||||||
test_path = os.path.join(src_root, 'test', 'libcxx', 'inclusions')
|
test_path = os.path.join(src_root, "test", "libcxx", "inclusions")
|
||||||
assert os.path.exists(test_path)
|
assert os.path.exists(test_path)
|
||||||
assert os.path.exists(os.path.join(test_path, 'algorithm.inclusions.compile.pass.cpp'))
|
assert os.path.exists(
|
||||||
|
os.path.join(test_path, "algorithm.inclusions.compile.pass.cpp")
|
||||||
|
)
|
||||||
return script_name, src_root, test_path
|
return script_name, src_root, test_path
|
||||||
|
|
||||||
|
|
||||||
@ -93,46 +95,46 @@ assert all(v == sorted(v) for k, v in mandatory_inclusions.items())
|
|||||||
# <thread> should be marked as UNSUPPORTED, because including <thread>
|
# <thread> should be marked as UNSUPPORTED, because including <thread>
|
||||||
# is a hard error in that case.
|
# is a hard error in that case.
|
||||||
lit_markup = {
|
lit_markup = {
|
||||||
"barrier": ["UNSUPPORTED: no-threads"],
|
"barrier": ["UNSUPPORTED: no-threads"],
|
||||||
"filesystem": ["UNSUPPORTED: no-filesystem"],
|
"filesystem": ["UNSUPPORTED: no-filesystem"],
|
||||||
"iomanip": ["UNSUPPORTED: no-localization"],
|
"iomanip": ["UNSUPPORTED: no-localization"],
|
||||||
"ios": ["UNSUPPORTED: no-localization"],
|
"ios": ["UNSUPPORTED: no-localization"],
|
||||||
"iostream": ["UNSUPPORTED: no-localization"],
|
"iostream": ["UNSUPPORTED: no-localization"],
|
||||||
"istream": ["UNSUPPORTED: no-localization"],
|
"istream": ["UNSUPPORTED: no-localization"],
|
||||||
"latch": ["UNSUPPORTED: no-threads"],
|
"latch": ["UNSUPPORTED: no-threads"],
|
||||||
"locale": ["UNSUPPORTED: no-localization"],
|
"locale": ["UNSUPPORTED: no-localization"],
|
||||||
"mutex": ["UNSUPPORTED: no-threads"],
|
"mutex": ["UNSUPPORTED: no-threads"],
|
||||||
"ostream": ["UNSUPPORTED: no-localization"],
|
"ostream": ["UNSUPPORTED: no-localization"],
|
||||||
"regex": ["UNSUPPORTED: no-localization"],
|
"regex": ["UNSUPPORTED: no-localization"],
|
||||||
"semaphore": ["UNSUPPORTED: no-threads"],
|
"semaphore": ["UNSUPPORTED: no-threads"],
|
||||||
"shared_mutex": ["UNSUPPORTED: no-threads"],
|
"shared_mutex": ["UNSUPPORTED: no-threads"],
|
||||||
"thread": ["UNSUPPORTED: no-threads"]
|
"thread": ["UNSUPPORTED: no-threads"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_std_ver_test(includee):
|
def get_std_ver_test(includee):
|
||||||
v = new_in_version.get(includee, "03")
|
v = new_in_version.get(includee, "03")
|
||||||
if v == "03":
|
if v == "03":
|
||||||
return ''
|
return ""
|
||||||
versions = ["03", "11", "14", "17", "20"]
|
versions = ["03", "11", "14", "17", "20"]
|
||||||
return 'TEST_STD_VER > {} && '.format(max(i for i in versions if i < v))
|
return "TEST_STD_VER > {} && ".format(max(i for i in versions if i < v))
|
||||||
|
|
||||||
|
|
||||||
def get_unsupported_line(includee):
|
def get_unsupported_line(includee):
|
||||||
v = new_in_version.get(includee, "03")
|
v = new_in_version.get(includee, "03")
|
||||||
return {
|
return {
|
||||||
"03": [],
|
"03": [],
|
||||||
"11": ['UNSUPPORTED: c++03'],
|
"11": ["UNSUPPORTED: c++03"],
|
||||||
"14": ['UNSUPPORTED: c++03, c++11'],
|
"14": ["UNSUPPORTED: c++03, c++11"],
|
||||||
"17": ['UNSUPPORTED: c++03, c++11, c++14'],
|
"17": ["UNSUPPORTED: c++03, c++11, c++14"],
|
||||||
"20": ['UNSUPPORTED: c++03, c++11, c++14, c++17'],
|
"20": ["UNSUPPORTED: c++03, c++11, c++14, c++17"],
|
||||||
"23": ['UNSUPPORTED: c++03, c++11, c++14, c++17, c++20'],
|
"23": ["UNSUPPORTED: c++03, c++11, c++14, c++17, c++20"],
|
||||||
"26": ['UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23'],
|
"26": ["UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23"],
|
||||||
}[v]
|
}[v]
|
||||||
|
|
||||||
|
|
||||||
def get_libcpp_header_symbol(header_name):
|
def get_libcpp_header_symbol(header_name):
|
||||||
return '_LIBCPP_' + header_name.upper().replace('.', '_')
|
return "_LIBCPP_" + header_name.upper().replace(".", "_")
|
||||||
|
|
||||||
|
|
||||||
def get_includer_symbol_test(includer):
|
def get_includer_symbol_test(includer):
|
||||||
@ -157,7 +159,9 @@ def get_ifdef(includer, includee):
|
|||||||
""".strip().format(
|
""".strip().format(
|
||||||
includee_test=get_std_ver_test(includee),
|
includee_test=get_std_ver_test(includee),
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
message="<{}> should include <{}> in C++{} and later".format(includer, includee, version)
|
message="<{}> should include <{}> in C++{} and later".format(
|
||||||
|
includer, includee, version
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -193,15 +197,19 @@ def produce_tests():
|
|||||||
test_body = test_body_template.format(
|
test_body = test_body_template.format(
|
||||||
script_name=script_name,
|
script_name=script_name,
|
||||||
header=includer,
|
header=includer,
|
||||||
markup=('\n' + '\n'.join('// ' + m for m in markup_tags) + '\n') if markup_tags else '',
|
markup=("\n" + "\n".join("// " + m for m in markup_tags) + "\n")
|
||||||
|
if markup_tags
|
||||||
|
else "",
|
||||||
test_includers_symbol=get_includer_symbol_test(includer),
|
test_includers_symbol=get_includer_symbol_test(includer),
|
||||||
test_per_includee='\n'.join(get_ifdef(includer, includee) for includee in includees),
|
test_per_includee="\n".join(
|
||||||
|
get_ifdef(includer, includee) for includee in includees
|
||||||
|
),
|
||||||
)
|
)
|
||||||
test_name = "{header}.inclusions.compile.pass.cpp".format(header=includer)
|
test_name = "{header}.inclusions.compile.pass.cpp".format(header=includer)
|
||||||
out_path = os.path.join(test_path, test_name)
|
out_path = os.path.join(test_path, test_name)
|
||||||
with open(out_path, 'w', newline='\n') as f:
|
with open(out_path, "w", newline="\n") as f:
|
||||||
f.write(test_body + '\n')
|
f.write(test_body + "\n")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
produce_tests()
|
produce_tests()
|
||||||
|
@ -16,12 +16,9 @@ header_restrictions = {
|
|||||||
"shared_mutex": "!defined(_LIBCPP_HAS_NO_THREADS)",
|
"shared_mutex": "!defined(_LIBCPP_HAS_NO_THREADS)",
|
||||||
"stdatomic.h": "__cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)",
|
"stdatomic.h": "__cplusplus > 202002L && !defined(_LIBCPP_HAS_NO_THREADS)",
|
||||||
"thread": "!defined(_LIBCPP_HAS_NO_THREADS)",
|
"thread": "!defined(_LIBCPP_HAS_NO_THREADS)",
|
||||||
|
|
||||||
"filesystem": "!defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)",
|
"filesystem": "!defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)",
|
||||||
|
|
||||||
# TODO(LLVM-17): simplify this to __cplusplus >= 202002L
|
# TODO(LLVM-17): simplify this to __cplusplus >= 202002L
|
||||||
"coroutine": "(defined(__cpp_impl_coroutine) && __cpp_impl_coroutine >= 201902L) || (defined(__cpp_coroutines) && __cpp_coroutines >= 201703L)",
|
"coroutine": "(defined(__cpp_impl_coroutine) && __cpp_impl_coroutine >= 201902L) || (defined(__cpp_coroutines) && __cpp_coroutines >= 201703L)",
|
||||||
|
|
||||||
"clocale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
"clocale": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
||||||
"codecvt": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
"codecvt": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
||||||
"fstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM)",
|
"fstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION) && !defined(_LIBCPP_HAS_NO_FSTREAM)",
|
||||||
@ -36,12 +33,10 @@ header_restrictions = {
|
|||||||
"sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
"sstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
||||||
"streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
"streambuf": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
||||||
"strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
"strstream": "!defined(_LIBCPP_HAS_NO_LOCALIZATION)",
|
||||||
|
|
||||||
"wctype.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
"wctype.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
||||||
"cwctype": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
"cwctype": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
||||||
"cwchar": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
"cwchar": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
||||||
"wchar.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
"wchar.h": "!defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)",
|
||||||
|
|
||||||
"experimental/algorithm": "__cplusplus >= 201103L",
|
"experimental/algorithm": "__cplusplus >= 201103L",
|
||||||
"experimental/deque": "__cplusplus >= 201103L",
|
"experimental/deque": "__cplusplus >= 201103L",
|
||||||
"experimental/forward_list": "__cplusplus >= 201103L",
|
"experimental/forward_list": "__cplusplus >= 201103L",
|
||||||
@ -64,89 +59,133 @@ header_restrictions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private_headers_still_public_in_modules = [
|
private_headers_still_public_in_modules = [
|
||||||
'__assert', '__config',
|
"__assert",
|
||||||
'__config_site.in', '__debug', '__hash_table',
|
"__config",
|
||||||
'__threading_support', '__tree', '__undef_macros', '__verbose_abort'
|
"__config_site.in",
|
||||||
|
"__debug",
|
||||||
|
"__hash_table",
|
||||||
|
"__threading_support",
|
||||||
|
"__tree",
|
||||||
|
"__undef_macros",
|
||||||
|
"__verbose_abort",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def find_script(file):
|
def find_script(file):
|
||||||
"""Finds the script used to generate a file inside the file itself. The script is delimited by
|
"""Finds the script used to generate a file inside the file itself. The script is delimited by
|
||||||
BEGIN-SCRIPT and END-SCRIPT markers.
|
BEGIN-SCRIPT and END-SCRIPT markers.
|
||||||
"""
|
"""
|
||||||
with open(file, 'r') as f:
|
with open(file, "r") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
||||||
match = re.search(r'^BEGIN-SCRIPT$(.+)^END-SCRIPT$', content, flags=re.MULTILINE | re.DOTALL)
|
match = re.search(
|
||||||
|
r"^BEGIN-SCRIPT$(.+)^END-SCRIPT$", content, flags=re.MULTILINE | re.DOTALL
|
||||||
|
)
|
||||||
if not match:
|
if not match:
|
||||||
raise RuntimeError("Was unable to find a script delimited with BEGIN-SCRIPT/END-SCRIPT markers in {}".format(test_file))
|
raise RuntimeError(
|
||||||
|
"Was unable to find a script delimited with BEGIN-SCRIPT/END-SCRIPT markers in {}".format(
|
||||||
|
test_file
|
||||||
|
)
|
||||||
|
)
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
|
|
||||||
|
|
||||||
def execute_script(script, variables):
|
def execute_script(script, variables):
|
||||||
"""Executes the provided Mako template with the given variables available during the
|
"""Executes the provided Mako template with the given variables available during the
|
||||||
evaluation of the script, and returns the result.
|
evaluation of the script, and returns the result.
|
||||||
"""
|
"""
|
||||||
code = compile(script, 'fake-filename', 'exec')
|
code = compile(script, "fake-filename", "exec")
|
||||||
output = io.StringIO()
|
output = io.StringIO()
|
||||||
with contextlib.redirect_stdout(output):
|
with contextlib.redirect_stdout(output):
|
||||||
exec(code, variables)
|
exec(code, variables)
|
||||||
output = output.getvalue()
|
output = output.getvalue()
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def generate_new_file(file, new_content):
|
def generate_new_file(file, new_content):
|
||||||
"""Generates the new content of the file by inserting the new content in-between
|
"""Generates the new content of the file by inserting the new content in-between
|
||||||
two '// GENERATED-MARKER' markers located in the file.
|
two '// GENERATED-MARKER' markers located in the file.
|
||||||
"""
|
"""
|
||||||
with open(file, 'r') as f:
|
with open(file, "r") as f:
|
||||||
old_content = f.read()
|
old_content = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
before, begin_marker, _, end_marker, after = re.split(r'(// GENERATED-MARKER\n)', old_content, flags=re.MULTILINE | re.DOTALL)
|
before, begin_marker, _, end_marker, after = re.split(
|
||||||
|
r"(// GENERATED-MARKER\n)", old_content, flags=re.MULTILINE | re.DOTALL
|
||||||
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise RuntimeError("Failed to split {} based on markers, please make sure the file has exactly two '// GENERATED-MARKER' occurrences".format(file))
|
raise RuntimeError(
|
||||||
|
"Failed to split {} based on markers, please make sure the file has exactly two '// GENERATED-MARKER' occurrences".format(
|
||||||
|
file
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return before + begin_marker + new_content + end_marker + after
|
return before + begin_marker + new_content + end_marker + after
|
||||||
|
|
||||||
|
|
||||||
def produce(test_file, variables):
|
def produce(test_file, variables):
|
||||||
script = find_script(test_file)
|
script = find_script(test_file)
|
||||||
result = execute_script(script, variables)
|
result = execute_script(script, variables)
|
||||||
new_content = generate_new_file(test_file, result)
|
new_content = generate_new_file(test_file, result)
|
||||||
with open(test_file, 'w', newline='\n') as f:
|
with open(test_file, "w", newline="\n") as f:
|
||||||
f.write(new_content)
|
f.write(new_content)
|
||||||
|
|
||||||
|
|
||||||
def is_header(file):
|
def is_header(file):
|
||||||
"""Returns whether the given file is a header (i.e. not a directory or the modulemap file)."""
|
"""Returns whether the given file is a header (i.e. not a directory or the modulemap file)."""
|
||||||
return not file.is_dir() and not file.name == 'module.modulemap.in' and file.name != 'libcxx.imp'
|
return (
|
||||||
|
not file.is_dir()
|
||||||
|
and not file.name == "module.modulemap.in"
|
||||||
|
and file.name != "libcxx.imp"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
monorepo_root = pathlib.Path(
|
||||||
include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include'))
|
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
test = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'test'))
|
)
|
||||||
assert(monorepo_root.exists())
|
include = pathlib.Path(os.path.join(monorepo_root, "libcxx", "include"))
|
||||||
|
test = pathlib.Path(os.path.join(monorepo_root, "libcxx", "test"))
|
||||||
|
assert monorepo_root.exists()
|
||||||
|
|
||||||
toplevel_headers = sorted(str(p.relative_to(include)) for p in include.glob('[a-z]*') if is_header(p))
|
toplevel_headers = sorted(
|
||||||
experimental_headers = sorted(str(p.relative_to(include)) for p in include.glob('experimental/[a-z]*') if is_header(p))
|
str(p.relative_to(include)) for p in include.glob("[a-z]*") if is_header(p)
|
||||||
public_headers = toplevel_headers + experimental_headers
|
)
|
||||||
private_headers = sorted(str(p.relative_to(include)) for p in include.rglob('*') if is_header(p) and str(p.relative_to(include)).startswith('__') and not p.name.startswith('pstl'))
|
experimental_headers = sorted(
|
||||||
|
str(p.relative_to(include))
|
||||||
|
for p in include.glob("experimental/[a-z]*")
|
||||||
|
if is_header(p)
|
||||||
|
)
|
||||||
|
public_headers = toplevel_headers + experimental_headers
|
||||||
|
private_headers = sorted(
|
||||||
|
str(p.relative_to(include))
|
||||||
|
for p in include.rglob("*")
|
||||||
|
if is_header(p)
|
||||||
|
and str(p.relative_to(include)).startswith("__")
|
||||||
|
and not p.name.startswith("pstl")
|
||||||
|
)
|
||||||
variables = {
|
variables = {
|
||||||
'toplevel_headers': toplevel_headers,
|
"toplevel_headers": toplevel_headers,
|
||||||
'experimental_headers': experimental_headers,
|
"experimental_headers": experimental_headers,
|
||||||
'public_headers': public_headers,
|
"public_headers": public_headers,
|
||||||
'private_headers': private_headers,
|
"private_headers": private_headers,
|
||||||
'header_restrictions': header_restrictions,
|
"header_restrictions": header_restrictions,
|
||||||
'private_headers_still_public_in_modules': private_headers_still_public_in_modules
|
"private_headers_still_public_in_modules": private_headers_still_public_in_modules,
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(test.joinpath('libcxx/assertions/headers_declare_verbose_abort.sh.cpp'), variables)
|
produce(
|
||||||
produce(test.joinpath('libcxx/clang_tidy.sh.cpp'), variables)
|
test.joinpath("libcxx/assertions/headers_declare_verbose_abort.sh.cpp"),
|
||||||
produce(test.joinpath('libcxx/double_include.sh.cpp'), variables)
|
variables,
|
||||||
produce(test.joinpath('libcxx/min_max_macros.compile.pass.cpp'), variables)
|
)
|
||||||
produce(test.joinpath('libcxx/modules_include.sh.cpp'), variables)
|
produce(test.joinpath("libcxx/clang_tidy.sh.cpp"), variables)
|
||||||
produce(test.joinpath('libcxx/nasty_macros.compile.pass.cpp'), variables)
|
produce(test.joinpath("libcxx/double_include.sh.cpp"), variables)
|
||||||
produce(test.joinpath('libcxx/no_assert_include.compile.pass.cpp'), variables)
|
produce(test.joinpath("libcxx/min_max_macros.compile.pass.cpp"), variables)
|
||||||
produce(test.joinpath('libcxx/private_headers.verify.cpp'), variables)
|
produce(test.joinpath("libcxx/modules_include.sh.cpp"), variables)
|
||||||
produce(test.joinpath('libcxx/transitive_includes.sh.cpp'), variables)
|
produce(test.joinpath("libcxx/nasty_macros.compile.pass.cpp"), variables)
|
||||||
|
produce(test.joinpath("libcxx/no_assert_include.compile.pass.cpp"), variables)
|
||||||
|
produce(test.joinpath("libcxx/private_headers.verify.cpp"), variables)
|
||||||
|
produce(test.joinpath("libcxx/transitive_includes.sh.cpp"), variables)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -2,13 +2,17 @@
|
|||||||
|
|
||||||
import os, pathlib, sys
|
import os, pathlib, sys
|
||||||
|
|
||||||
|
|
||||||
def generate(private, public):
|
def generate(private, public):
|
||||||
return f'{{ include: [ "{private}", "private", "<{public}>", "public" ] }}'
|
return f'{{ include: [ "{private}", "private", "<{public}>", "public" ] }}'
|
||||||
|
|
||||||
|
|
||||||
def panic(file):
|
def panic(file):
|
||||||
print(f'========== {__file__} error ==========', file=sys.stderr)
|
print(f"========== {__file__} error ==========", file=sys.stderr)
|
||||||
print(f'\tFile \'{file}\' is a top-level detail header without a mapping', file=sys.stderr)
|
print(
|
||||||
|
f"\tFile '{file}' is a top-level detail header without a mapping",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@ -18,50 +22,75 @@ def generate_map(include):
|
|||||||
c_headers = []
|
c_headers = []
|
||||||
|
|
||||||
for i in include.iterdir():
|
for i in include.iterdir():
|
||||||
if i.is_dir() and i.name.startswith('__'):
|
if i.is_dir() and i.name.startswith("__"):
|
||||||
detail_directories.append(f'{i.name}')
|
detail_directories.append(f"{i.name}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if i.name.startswith('__'):
|
if i.name.startswith("__"):
|
||||||
detail_files.append(i.name)
|
detail_files.append(i.name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if i.name.endswith('.h'):
|
if i.name.endswith(".h"):
|
||||||
c_headers.append(i.name)
|
c_headers.append(i.name)
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
temporary_mappings = {'__locale_dir' : 'locale'}
|
temporary_mappings = {"__locale_dir": "locale"}
|
||||||
for i in detail_directories:
|
for i in detail_directories:
|
||||||
public_header = temporary_mappings.get(i, i.lstrip('_'))
|
public_header = temporary_mappings.get(i, i.lstrip("_"))
|
||||||
result.append(f'{generate(f"@<{i}/.*>", public_header)},')
|
result.append(f'{generate(f"@<{i}/.*>", public_header)},')
|
||||||
|
|
||||||
for i in detail_files:
|
for i in detail_files:
|
||||||
public = []
|
public = []
|
||||||
if i == '__assert': continue
|
if i == "__assert":
|
||||||
elif i == '__availability': continue
|
continue
|
||||||
elif i == '__bit_reference': continue
|
elif i == "__availability":
|
||||||
elif i == '__bits': public = ['bits']
|
continue
|
||||||
elif i == '__config_site.in': continue
|
elif i == "__bit_reference":
|
||||||
elif i == '__config': continue
|
continue
|
||||||
elif i == '__debug': continue
|
elif i == "__bits":
|
||||||
elif i == '__errc': continue
|
public = ["bits"]
|
||||||
elif i == '__hash_table': public = ['unordered_map', 'unordered_set']
|
elif i == "__config_site.in":
|
||||||
elif i == '__locale': public = ['locale']
|
continue
|
||||||
elif i == '__mbstate_t.h': continue
|
elif i == "__config":
|
||||||
elif i == '__mutex_base': continue
|
continue
|
||||||
elif i == '__node_handle': public = ['map', 'set', 'unordered_map', 'unordered_set']
|
elif i == "__debug":
|
||||||
elif i == '__pstl_algorithm': continue
|
continue
|
||||||
elif i == '__pstl_config_site.in': continue
|
elif i == "__errc":
|
||||||
elif i == '__pstl_execution': continue
|
continue
|
||||||
elif i == '__pstl_memory': continue
|
elif i == "__hash_table":
|
||||||
elif i == '__pstl_numeric': continue
|
public = ["unordered_map", "unordered_set"]
|
||||||
elif i == '__split_buffer': public = ['deque', 'vector']
|
elif i == "__locale":
|
||||||
elif i == '__std_mbstate_t.h': continue
|
public = ["locale"]
|
||||||
elif i == '__threading_support': public = ['atomic', 'mutex', 'semaphore', 'thread']
|
elif i == "__mbstate_t.h":
|
||||||
elif i == '__tree': public = ['map', 'set']
|
continue
|
||||||
elif i == '__undef_macros': continue
|
elif i == "__mutex_base":
|
||||||
elif i == '__verbose_abort': continue
|
continue
|
||||||
else: panic(i)
|
elif i == "__node_handle":
|
||||||
|
public = ["map", "set", "unordered_map", "unordered_set"]
|
||||||
|
elif i == "__pstl_algorithm":
|
||||||
|
continue
|
||||||
|
elif i == "__pstl_config_site.in":
|
||||||
|
continue
|
||||||
|
elif i == "__pstl_execution":
|
||||||
|
continue
|
||||||
|
elif i == "__pstl_memory":
|
||||||
|
continue
|
||||||
|
elif i == "__pstl_numeric":
|
||||||
|
continue
|
||||||
|
elif i == "__split_buffer":
|
||||||
|
public = ["deque", "vector"]
|
||||||
|
elif i == "__std_mbstate_t.h":
|
||||||
|
continue
|
||||||
|
elif i == "__threading_support":
|
||||||
|
public = ["atomic", "mutex", "semaphore", "thread"]
|
||||||
|
elif i == "__tree":
|
||||||
|
public = ["map", "set"]
|
||||||
|
elif i == "__undef_macros":
|
||||||
|
continue
|
||||||
|
elif i == "__verbose_abort":
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
panic(i)
|
||||||
|
|
||||||
for p in public:
|
for p in public:
|
||||||
result.append(f'{generate(f"<{i}>", p)},')
|
result.append(f'{generate(f"<{i}>", p)},')
|
||||||
@ -69,16 +98,19 @@ def generate_map(include):
|
|||||||
result.sort()
|
result.sort()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
monorepo_root = pathlib.Path(
|
||||||
assert(monorepo_root.exists())
|
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include'))
|
)
|
||||||
|
assert monorepo_root.exists()
|
||||||
|
include = pathlib.Path(os.path.join(monorepo_root, "libcxx", "include"))
|
||||||
|
|
||||||
mapping = generate_map(include)
|
mapping = generate_map(include)
|
||||||
data = '[\n ' + '\n '.join(mapping) + '\n]\n'
|
data = "[\n " + "\n ".join(mapping) + "\n]\n"
|
||||||
with open(f'{include}/libcxx.imp', 'w') as f:
|
with open(f"{include}/libcxx.imp", "w") as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -326,10 +326,7 @@ def generate_data_tables() -> str:
|
|||||||
Generate Unicode data for [format.string.std]/12
|
Generate Unicode data for [format.string.std]/12
|
||||||
"""
|
"""
|
||||||
east_asian_width_path = (
|
east_asian_width_path = (
|
||||||
Path(__file__).absolute().parent
|
Path(__file__).absolute().parent / "data" / "unicode" / "EastAsianWidth.txt"
|
||||||
/ "data"
|
|
||||||
/ "unicode"
|
|
||||||
/ "EastAsianWidth.txt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
properties = list()
|
properties = list()
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
"""libcxx python utilities"""
|
"""libcxx python utilities"""
|
||||||
|
|
||||||
__author__ = 'Eric Fiselier'
|
__author__ = "Eric Fiselier"
|
||||||
__email__ = 'eric@efcs.ca'
|
__email__ = "eric@efcs.ca"
|
||||||
__versioninfo__ = (0, 1, 0)
|
__versioninfo__ = (0, 1, 0)
|
||||||
__version__ = ' '.join(str(v) for v in __versioninfo__) + 'dev'
|
__version__ = " ".join(str(v) for v in __versioninfo__) + "dev"
|
||||||
|
|
||||||
__all__ = []
|
__all__ = []
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
"""libcxx abi symbol checker"""
|
"""libcxx abi symbol checker"""
|
||||||
|
|
||||||
__author__ = 'Eric Fiselier'
|
__author__ = "Eric Fiselier"
|
||||||
__email__ = 'eric@efcs.ca'
|
__email__ = "eric@efcs.ca"
|
||||||
__versioninfo__ = (0, 1, 0)
|
__versioninfo__ = (0, 1, 0)
|
||||||
__version__ = ' '.join(str(v) for v in __versioninfo__) + 'dev'
|
__version__ = " ".join(str(v) for v in __versioninfo__) + "dev"
|
||||||
|
|
||||||
__all__ = ['diff', 'extract', 'util']
|
__all__ = ["diff", "extract", "util"]
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
|
# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
"""
|
"""
|
||||||
diff - A set of functions for diff-ing two symbol lists.
|
diff - A set of functions for diff-ing two symbol lists.
|
||||||
"""
|
"""
|
||||||
@ -14,15 +14,15 @@ from libcxx.sym_check import util
|
|||||||
|
|
||||||
|
|
||||||
def _symbol_difference(lhs, rhs):
|
def _symbol_difference(lhs, rhs):
|
||||||
lhs_names = set(((n['name'], n['type']) for n in lhs))
|
lhs_names = set(((n["name"], n["type"]) for n in lhs))
|
||||||
rhs_names = set(((n['name'], n['type']) for n in rhs))
|
rhs_names = set(((n["name"], n["type"]) for n in rhs))
|
||||||
diff_names = lhs_names - rhs_names
|
diff_names = lhs_names - rhs_names
|
||||||
return [n for n in lhs if (n['name'], n['type']) in diff_names]
|
return [n for n in lhs if (n["name"], n["type"]) in diff_names]
|
||||||
|
|
||||||
|
|
||||||
def _find_by_key(sym_list, k):
|
def _find_by_key(sym_list, k):
|
||||||
for sym in sym_list:
|
for sym in sym_list:
|
||||||
if sym['name'] == k:
|
if sym["name"] == k:
|
||||||
return sym
|
return sym
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -40,9 +40,8 @@ def changed_symbols(old, new):
|
|||||||
for old_sym in old:
|
for old_sym in old:
|
||||||
if old_sym in new:
|
if old_sym in new:
|
||||||
continue
|
continue
|
||||||
new_sym = _find_by_key(new, old_sym['name'])
|
new_sym = _find_by_key(new, old_sym["name"])
|
||||||
if (new_sym is not None and not new_sym in old
|
if new_sym is not None and not new_sym in old and old_sym != new_sym:
|
||||||
and old_sym != new_sym):
|
|
||||||
changed += [(old_sym, new_sym)]
|
changed += [(old_sym, new_sym)]
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
@ -54,49 +53,51 @@ def diff(old, new):
|
|||||||
return added, removed, changed
|
return added, removed, changed
|
||||||
|
|
||||||
|
|
||||||
def report_diff(added_syms, removed_syms, changed_syms, names_only=False,
|
def report_diff(
|
||||||
demangle=True):
|
added_syms, removed_syms, changed_syms, names_only=False, demangle=True
|
||||||
|
):
|
||||||
def maybe_demangle(name):
|
def maybe_demangle(name):
|
||||||
return util.demangle_symbol(name) if demangle else name
|
return util.demangle_symbol(name) if demangle else name
|
||||||
|
|
||||||
report = ''
|
report = ""
|
||||||
for sym in added_syms:
|
for sym in added_syms:
|
||||||
report += 'Symbol added: %s\n' % maybe_demangle(sym['name'])
|
report += "Symbol added: %s\n" % maybe_demangle(sym["name"])
|
||||||
if not names_only:
|
if not names_only:
|
||||||
report += ' %s\n\n' % sym
|
report += " %s\n\n" % sym
|
||||||
if added_syms and names_only:
|
if added_syms and names_only:
|
||||||
report += '\n'
|
report += "\n"
|
||||||
for sym in removed_syms:
|
for sym in removed_syms:
|
||||||
report += 'SYMBOL REMOVED: %s\n' % maybe_demangle(sym['name'])
|
report += "SYMBOL REMOVED: %s\n" % maybe_demangle(sym["name"])
|
||||||
if not names_only:
|
if not names_only:
|
||||||
report += ' %s\n\n' % sym
|
report += " %s\n\n" % sym
|
||||||
if removed_syms and names_only:
|
if removed_syms and names_only:
|
||||||
report += '\n'
|
report += "\n"
|
||||||
if not names_only:
|
if not names_only:
|
||||||
for sym_pair in changed_syms:
|
for sym_pair in changed_syms:
|
||||||
old_sym, new_sym = sym_pair
|
old_sym, new_sym = sym_pair
|
||||||
old_str = '\n OLD SYMBOL: %s' % old_sym
|
old_str = "\n OLD SYMBOL: %s" % old_sym
|
||||||
new_str = '\n NEW SYMBOL: %s' % new_sym
|
new_str = "\n NEW SYMBOL: %s" % new_sym
|
||||||
report += ('SYMBOL CHANGED: %s%s%s\n\n' %
|
report += "SYMBOL CHANGED: %s%s%s\n\n" % (
|
||||||
(maybe_demangle(old_sym['name']),
|
maybe_demangle(old_sym["name"]),
|
||||||
old_str, new_str))
|
old_str,
|
||||||
|
new_str,
|
||||||
|
)
|
||||||
|
|
||||||
added = bool(len(added_syms) != 0)
|
added = bool(len(added_syms) != 0)
|
||||||
abi_break = bool(len(removed_syms))
|
abi_break = bool(len(removed_syms))
|
||||||
if not names_only:
|
if not names_only:
|
||||||
abi_break = abi_break or len(changed_syms)
|
abi_break = abi_break or len(changed_syms)
|
||||||
if added or abi_break:
|
if added or abi_break:
|
||||||
report += 'Summary\n'
|
report += "Summary\n"
|
||||||
report += ' Added: %d\n' % len(added_syms)
|
report += " Added: %d\n" % len(added_syms)
|
||||||
report += ' Removed: %d\n' % len(removed_syms)
|
report += " Removed: %d\n" % len(removed_syms)
|
||||||
if not names_only:
|
if not names_only:
|
||||||
report += ' Changed: %d\n' % len(changed_syms)
|
report += " Changed: %d\n" % len(changed_syms)
|
||||||
if not abi_break:
|
if not abi_break:
|
||||||
report += 'Symbols added.'
|
report += "Symbols added."
|
||||||
else:
|
else:
|
||||||
report += 'ABI BREAKAGE: SYMBOLS ADDED OR REMOVED!'
|
report += "ABI BREAKAGE: SYMBOLS ADDED OR REMOVED!"
|
||||||
else:
|
else:
|
||||||
report += 'Symbols match.'
|
report += "Symbols match."
|
||||||
is_different = abi_break or bool(len(added_syms)) \
|
is_different = abi_break or bool(len(added_syms)) or bool(len(changed_syms))
|
||||||
or bool(len(changed_syms))
|
|
||||||
return report, abi_break, is_different
|
return report, abi_break, is_different
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
|
# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
"""
|
"""
|
||||||
extract - A set of function that extract symbol lists from shared libraries.
|
extract - A set of function that extract symbol lists from shared libraries.
|
||||||
"""
|
"""
|
||||||
@ -18,7 +18,8 @@ import sys
|
|||||||
|
|
||||||
from libcxx.sym_check import util
|
from libcxx.sym_check import util
|
||||||
|
|
||||||
extract_ignore_names = ['_init', '_fini']
|
extract_ignore_names = ["_init", "_fini"]
|
||||||
|
|
||||||
|
|
||||||
class NMExtractor(object):
|
class NMExtractor(object):
|
||||||
"""
|
"""
|
||||||
@ -30,7 +31,7 @@ class NMExtractor(object):
|
|||||||
"""
|
"""
|
||||||
Search for the nm executable and return the path.
|
Search for the nm executable and return the path.
|
||||||
"""
|
"""
|
||||||
return shutil.which('nm')
|
return shutil.which("nm")
|
||||||
|
|
||||||
def __init__(self, static_lib):
|
def __init__(self, static_lib):
|
||||||
"""
|
"""
|
||||||
@ -43,11 +44,10 @@ class NMExtractor(object):
|
|||||||
print("ERROR: Could not find nm")
|
print("ERROR: Could not find nm")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self.static_lib = static_lib
|
self.static_lib = static_lib
|
||||||
self.flags = ['-P', '-g']
|
self.flags = ["-P", "-g"]
|
||||||
if sys.platform.startswith('aix'):
|
if sys.platform.startswith("aix"):
|
||||||
# AIX nm demangles symbols by default, so suppress that.
|
# AIX nm demangles symbols by default, so suppress that.
|
||||||
self.flags.append('-C')
|
self.flags.append("-C")
|
||||||
|
|
||||||
|
|
||||||
def extract(self, lib):
|
def extract(self, lib):
|
||||||
"""
|
"""
|
||||||
@ -56,8 +56,7 @@ class NMExtractor(object):
|
|||||||
"""
|
"""
|
||||||
cmd = [self.nm_exe] + self.flags + [lib]
|
cmd = [self.nm_exe] + self.flags + [lib]
|
||||||
out = subprocess.check_output(cmd).decode()
|
out = subprocess.check_output(cmd).decode()
|
||||||
fmt_syms = (self._extract_sym(l)
|
fmt_syms = (self._extract_sym(l) for l in out.splitlines() if l.strip())
|
||||||
for l in out.splitlines() if l.strip())
|
|
||||||
# Cast symbol to string.
|
# Cast symbol to string.
|
||||||
final_syms = (repr(s) for s in fmt_syms if self._want_sym(s))
|
final_syms = (repr(s) for s in fmt_syms if self._want_sym(s))
|
||||||
# Make unique and sort strings.
|
# Make unique and sort strings.
|
||||||
@ -71,15 +70,15 @@ class NMExtractor(object):
|
|||||||
if len(bits) < 2:
|
if len(bits) < 2:
|
||||||
return None
|
return None
|
||||||
new_sym = {
|
new_sym = {
|
||||||
'name': bits[0],
|
"name": bits[0],
|
||||||
'type': bits[1],
|
"type": bits[1],
|
||||||
'is_defined': (bits[1].lower() != 'u')
|
"is_defined": (bits[1].lower() != "u"),
|
||||||
}
|
}
|
||||||
new_sym['name'] = new_sym['name'].replace('@@', '@')
|
new_sym["name"] = new_sym["name"].replace("@@", "@")
|
||||||
new_sym = self._transform_sym_type(new_sym)
|
new_sym = self._transform_sym_type(new_sym)
|
||||||
# NM types which we want to save the size for.
|
# NM types which we want to save the size for.
|
||||||
if new_sym['type'] == 'OBJECT' and len(bits) > 3:
|
if new_sym["type"] == "OBJECT" and len(bits) > 3:
|
||||||
new_sym['size'] = int(bits[3], 16)
|
new_sym["size"] = int(bits[3], 16)
|
||||||
return new_sym
|
return new_sym
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -89,11 +88,14 @@ class NMExtractor(object):
|
|||||||
"""
|
"""
|
||||||
if sym is None or len(sym) < 2:
|
if sym is None or len(sym) < 2:
|
||||||
return False
|
return False
|
||||||
if sym['name'] in extract_ignore_names:
|
if sym["name"] in extract_ignore_names:
|
||||||
return False
|
return False
|
||||||
bad_types = ['t', 'b', 'r', 'd', 'w']
|
bad_types = ["t", "b", "r", "d", "w"]
|
||||||
return (sym['type'] not in bad_types
|
return sym["type"] not in bad_types and sym["name"] not in [
|
||||||
and sym['name'] not in ['__bss_start', '_end', '_edata'])
|
"__bss_start",
|
||||||
|
"_end",
|
||||||
|
"_edata",
|
||||||
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _transform_sym_type(sym):
|
def _transform_sym_type(sym):
|
||||||
@ -101,14 +103,15 @@ class NMExtractor(object):
|
|||||||
Map the nm single letter output for type to either FUNC or OBJECT.
|
Map the nm single letter output for type to either FUNC or OBJECT.
|
||||||
If the type is not recognized it is left unchanged.
|
If the type is not recognized it is left unchanged.
|
||||||
"""
|
"""
|
||||||
func_types = ['T', 'W']
|
func_types = ["T", "W"]
|
||||||
obj_types = ['B', 'D', 'R', 'V', 'S']
|
obj_types = ["B", "D", "R", "V", "S"]
|
||||||
if sym['type'] in func_types:
|
if sym["type"] in func_types:
|
||||||
sym['type'] = 'FUNC'
|
sym["type"] = "FUNC"
|
||||||
elif sym['type'] in obj_types:
|
elif sym["type"] in obj_types:
|
||||||
sym['type'] = 'OBJECT'
|
sym["type"] = "OBJECT"
|
||||||
return sym
|
return sym
|
||||||
|
|
||||||
|
|
||||||
class ReadElfExtractor(object):
|
class ReadElfExtractor(object):
|
||||||
"""
|
"""
|
||||||
ReadElfExtractor - Extract symbol lists from libraries using readelf.
|
ReadElfExtractor - Extract symbol lists from libraries using readelf.
|
||||||
@ -119,7 +122,7 @@ class ReadElfExtractor(object):
|
|||||||
"""
|
"""
|
||||||
Search for the readelf executable and return the path.
|
Search for the readelf executable and return the path.
|
||||||
"""
|
"""
|
||||||
return shutil.which('readelf')
|
return shutil.which("readelf")
|
||||||
|
|
||||||
def __init__(self, static_lib):
|
def __init__(self, static_lib):
|
||||||
"""
|
"""
|
||||||
@ -133,7 +136,7 @@ class ReadElfExtractor(object):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# TODO: Support readelf for reading symbols from archives
|
# TODO: Support readelf for reading symbols from archives
|
||||||
assert not static_lib and "RealElf does not yet support static libs"
|
assert not static_lib and "RealElf does not yet support static libs"
|
||||||
self.flags = ['--wide', '--symbols']
|
self.flags = ["--wide", "--symbols"]
|
||||||
|
|
||||||
def extract(self, lib):
|
def extract(self, lib):
|
||||||
"""
|
"""
|
||||||
@ -155,18 +158,18 @@ class ReadElfExtractor(object):
|
|||||||
if len(parts) == 7:
|
if len(parts) == 7:
|
||||||
continue
|
continue
|
||||||
new_sym = {
|
new_sym = {
|
||||||
'name': parts[7],
|
"name": parts[7],
|
||||||
'size': int(parts[2]),
|
"size": int(parts[2]),
|
||||||
'type': parts[3],
|
"type": parts[3],
|
||||||
'is_defined': (parts[6] != 'UND')
|
"is_defined": (parts[6] != "UND"),
|
||||||
}
|
}
|
||||||
assert new_sym['type'] in ['OBJECT', 'FUNC', 'NOTYPE', 'TLS']
|
assert new_sym["type"] in ["OBJECT", "FUNC", "NOTYPE", "TLS"]
|
||||||
if new_sym['name'] in extract_ignore_names:
|
if new_sym["name"] in extract_ignore_names:
|
||||||
continue
|
continue
|
||||||
if new_sym['type'] == 'NOTYPE':
|
if new_sym["type"] == "NOTYPE":
|
||||||
continue
|
continue
|
||||||
if new_sym['type'] == 'FUNC':
|
if new_sym["type"] == "FUNC":
|
||||||
del new_sym['size']
|
del new_sym["size"]
|
||||||
new_syms += [new_sym]
|
new_syms += [new_sym]
|
||||||
return new_syms
|
return new_syms
|
||||||
|
|
||||||
@ -190,98 +193,100 @@ class ReadElfExtractor(object):
|
|||||||
end = len(lines)
|
end = len(lines)
|
||||||
return lines[start:end]
|
return lines[start:end]
|
||||||
|
|
||||||
|
|
||||||
class AIXDumpExtractor(object):
|
class AIXDumpExtractor(object):
|
||||||
"""
|
"""
|
||||||
AIXDumpExtractor - Extract symbol lists from libraries using AIX dump.
|
AIXDumpExtractor - Extract symbol lists from libraries using AIX dump.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_tool():
|
def find_tool():
|
||||||
"""
|
"""
|
||||||
Search for the dump executable and return the path.
|
Search for the dump executable and return the path.
|
||||||
"""
|
"""
|
||||||
return shutil.which('dump')
|
return shutil.which("dump")
|
||||||
|
|
||||||
def __init__(self, static_lib):
|
def __init__(self, static_lib):
|
||||||
"""
|
"""
|
||||||
Initialize the dump executable and flags that will be used to
|
Initialize the dump executable and flags that will be used to
|
||||||
extract symbols from shared libraries.
|
extract symbols from shared libraries.
|
||||||
"""
|
"""
|
||||||
# TODO: Support dump for reading symbols from static libraries
|
# TODO: Support dump for reading symbols from static libraries
|
||||||
assert not static_lib and "static libs not yet supported with dump"
|
assert not static_lib and "static libs not yet supported with dump"
|
||||||
self.tool = self.find_tool()
|
self.tool = self.find_tool()
|
||||||
if self.tool is None:
|
if self.tool is None:
|
||||||
print("ERROR: Could not find dump")
|
print("ERROR: Could not find dump")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self.flags = ['-n', '-v']
|
self.flags = ["-n", "-v"]
|
||||||
object_mode = environ.get('OBJECT_MODE')
|
object_mode = environ.get("OBJECT_MODE")
|
||||||
if object_mode == '32':
|
if object_mode == "32":
|
||||||
self.flags += ['-X32']
|
self.flags += ["-X32"]
|
||||||
elif object_mode == '64':
|
elif object_mode == "64":
|
||||||
self.flags += ['-X64']
|
self.flags += ["-X64"]
|
||||||
else:
|
else:
|
||||||
self.flags += ['-X32_64']
|
self.flags += ["-X32_64"]
|
||||||
|
|
||||||
def extract(self, lib):
|
def extract(self, lib):
|
||||||
"""
|
"""
|
||||||
Extract symbols from a library and return the results as a dict of
|
Extract symbols from a library and return the results as a dict of
|
||||||
parsed symbols.
|
parsed symbols.
|
||||||
"""
|
"""
|
||||||
cmd = [self.tool] + self.flags + [lib]
|
cmd = [self.tool] + self.flags + [lib]
|
||||||
out = subprocess.check_output(cmd).decode()
|
out = subprocess.check_output(cmd).decode()
|
||||||
loader_syms = self.get_loader_symbol_table(out)
|
loader_syms = self.get_loader_symbol_table(out)
|
||||||
return self.process_syms(loader_syms)
|
return self.process_syms(loader_syms)
|
||||||
|
|
||||||
def process_syms(self, sym_list):
|
def process_syms(self, sym_list):
|
||||||
new_syms = []
|
new_syms = []
|
||||||
for s in sym_list:
|
for s in sym_list:
|
||||||
parts = s.split()
|
parts = s.split()
|
||||||
if not parts:
|
if not parts:
|
||||||
continue
|
continue
|
||||||
assert len(parts) == 8 or len(parts) == 7
|
assert len(parts) == 8 or len(parts) == 7
|
||||||
if len(parts) == 7:
|
if len(parts) == 7:
|
||||||
continue
|
continue
|
||||||
new_sym = {
|
new_sym = {
|
||||||
'name': parts[7],
|
"name": parts[7],
|
||||||
'type': 'FUNC' if parts[4] == 'DS' else 'OBJECT',
|
"type": "FUNC" if parts[4] == "DS" else "OBJECT",
|
||||||
'is_defined': (parts[5] != 'EXTref'),
|
"is_defined": (parts[5] != "EXTref"),
|
||||||
'storage_mapping_class': parts[4],
|
"storage_mapping_class": parts[4],
|
||||||
'import_export': parts[3]
|
"import_export": parts[3],
|
||||||
}
|
}
|
||||||
if new_sym['name'] in extract_ignore_names:
|
if new_sym["name"] in extract_ignore_names:
|
||||||
continue
|
continue
|
||||||
new_syms += [new_sym]
|
new_syms += [new_sym]
|
||||||
return new_syms
|
return new_syms
|
||||||
|
|
||||||
def get_loader_symbol_table(self, out):
|
def get_loader_symbol_table(self, out):
|
||||||
lines = out.splitlines()
|
lines = out.splitlines()
|
||||||
return filter(lambda n: re.match(r'^\[[0-9]+\]', n), lines)
|
return filter(lambda n: re.match(r"^\[[0-9]+\]", n), lines)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_shared_lib(lib):
|
def is_shared_lib(lib):
|
||||||
"""
|
"""
|
||||||
Check for the shared object flag in XCOFF headers of the input file or
|
Check for the shared object flag in XCOFF headers of the input file or
|
||||||
library archive.
|
library archive.
|
||||||
"""
|
"""
|
||||||
dump = AIXDumpExtractor.find_tool()
|
dump = AIXDumpExtractor.find_tool()
|
||||||
if dump is None:
|
if dump is None:
|
||||||
print("ERROR: Could not find dump")
|
print("ERROR: Could not find dump")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
cmd = [dump, '-X32_64', '-ov', lib]
|
cmd = [dump, "-X32_64", "-ov", lib]
|
||||||
out = subprocess.check_output(cmd).decode()
|
out = subprocess.check_output(cmd).decode()
|
||||||
return out.find("SHROBJ") != -1
|
return out.find("SHROBJ") != -1
|
||||||
|
|
||||||
|
|
||||||
def is_static_library(lib_file):
|
def is_static_library(lib_file):
|
||||||
"""
|
"""
|
||||||
Determine if a given library is static or shared.
|
Determine if a given library is static or shared.
|
||||||
"""
|
"""
|
||||||
if sys.platform.startswith('aix'):
|
if sys.platform.startswith("aix"):
|
||||||
# An AIX library could be both, but for simplicity assume it isn't.
|
# An AIX library could be both, but for simplicity assume it isn't.
|
||||||
return not AIXDumpExtractor.is_shared_lib(lib_file)
|
return not AIXDumpExtractor.is_shared_lib(lib_file)
|
||||||
else:
|
else:
|
||||||
_, ext = os.path.splitext(lib_file)
|
_, ext = os.path.splitext(lib_file)
|
||||||
return ext == '.a'
|
return ext == ".a"
|
||||||
|
|
||||||
|
|
||||||
def extract_symbols(lib_file, static_lib=None):
|
def extract_symbols(lib_file, static_lib=None):
|
||||||
"""
|
"""
|
||||||
@ -291,7 +296,7 @@ def extract_symbols(lib_file, static_lib=None):
|
|||||||
"""
|
"""
|
||||||
if static_lib is None:
|
if static_lib is None:
|
||||||
static_lib = is_static_library(lib_file)
|
static_lib = is_static_library(lib_file)
|
||||||
if sys.platform.startswith('aix'):
|
if sys.platform.startswith("aix"):
|
||||||
extractor = AIXDumpExtractor(static_lib=static_lib)
|
extractor = AIXDumpExtractor(static_lib=static_lib)
|
||||||
elif ReadElfExtractor.find_tool() and not static_lib:
|
elif ReadElfExtractor.find_tool() and not static_lib:
|
||||||
extractor = ReadElfExtractor(static_lib=static_lib)
|
extractor = ReadElfExtractor(static_lib=static_lib)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
|
# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80:
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
"""
|
"""
|
||||||
match - A set of functions for matching symbols in a list to a list of regexs
|
match - A set of functions for matching symbols in a list to a list of regexs
|
||||||
"""
|
"""
|
||||||
@ -14,19 +14,19 @@ import re
|
|||||||
|
|
||||||
|
|
||||||
def find_and_report_matching(symbol_list, regex_list):
|
def find_and_report_matching(symbol_list, regex_list):
|
||||||
report = ''
|
report = ""
|
||||||
found_count = 0
|
found_count = 0
|
||||||
for regex_str in regex_list:
|
for regex_str in regex_list:
|
||||||
report += 'Matching regex "%s":\n' % regex_str
|
report += 'Matching regex "%s":\n' % regex_str
|
||||||
matching_list = find_matching_symbols(symbol_list, regex_str)
|
matching_list = find_matching_symbols(symbol_list, regex_str)
|
||||||
if not matching_list:
|
if not matching_list:
|
||||||
report += ' No matches found\n\n'
|
report += " No matches found\n\n"
|
||||||
continue
|
continue
|
||||||
# else
|
# else
|
||||||
found_count += len(matching_list)
|
found_count += len(matching_list)
|
||||||
for m in matching_list:
|
for m in matching_list:
|
||||||
report += ' MATCHES: %s\n' % m['name']
|
report += " MATCHES: %s\n" % m["name"]
|
||||||
report += '\n'
|
report += "\n"
|
||||||
return found_count, report
|
return found_count, report
|
||||||
|
|
||||||
|
|
||||||
@ -34,6 +34,6 @@ def find_matching_symbols(symbol_list, regex_str):
|
|||||||
regex = re.compile(regex_str)
|
regex = re.compile(regex_str)
|
||||||
matching_list = []
|
matching_list = []
|
||||||
for s in symbol_list:
|
for s in symbol_list:
|
||||||
if regex.match(s['name']):
|
if regex.match(s["name"]):
|
||||||
matching_list += [s]
|
matching_list += [s]
|
||||||
return matching_list
|
return matching_list
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import ast
|
import ast
|
||||||
@ -26,16 +26,16 @@ def read_syms_from_file(filename):
|
|||||||
"""
|
"""
|
||||||
Read a list of symbols in from a file.
|
Read a list of symbols in from a file.
|
||||||
"""
|
"""
|
||||||
with open(filename, 'r') as f:
|
with open(filename, "r") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
return read_syms_from_list(data.splitlines())
|
return read_syms_from_list(data.splitlines())
|
||||||
|
|
||||||
|
|
||||||
def read_exclusions(filename):
|
def read_exclusions(filename):
|
||||||
with open(filename, 'r') as f:
|
with open(filename, "r") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
lines = [l.strip() for l in data.splitlines() if l.strip()]
|
lines = [l.strip() for l in data.splitlines() if l.strip()]
|
||||||
lines = [l for l in lines if not l.startswith('#')]
|
lines = [l for l in lines if not l.startswith("#")]
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
@ -43,24 +43,24 @@ def write_syms(sym_list, out=None, names_only=False, filter=None):
|
|||||||
"""
|
"""
|
||||||
Write a list of symbols to the file named by out.
|
Write a list of symbols to the file named by out.
|
||||||
"""
|
"""
|
||||||
out_str = ''
|
out_str = ""
|
||||||
out_list = sym_list
|
out_list = sym_list
|
||||||
out_list.sort(key=lambda x: x['name'])
|
out_list.sort(key=lambda x: x["name"])
|
||||||
if filter is not None:
|
if filter is not None:
|
||||||
out_list = filter(out_list)
|
out_list = filter(out_list)
|
||||||
if names_only:
|
if names_only:
|
||||||
out_list = [sym['name'] for sym in out_list]
|
out_list = [sym["name"] for sym in out_list]
|
||||||
for sym in out_list:
|
for sym in out_list:
|
||||||
# Use pformat for consistent ordering of keys.
|
# Use pformat for consistent ordering of keys.
|
||||||
out_str += pformat(sym, width=100000) + '\n'
|
out_str += pformat(sym, width=100000) + "\n"
|
||||||
if out is None:
|
if out is None:
|
||||||
sys.stdout.write(out_str)
|
sys.stdout.write(out_str)
|
||||||
else:
|
else:
|
||||||
with open(out, 'w') as f:
|
with open(out, "w") as f:
|
||||||
f.write(out_str)
|
f.write(out_str)
|
||||||
|
|
||||||
|
|
||||||
_cppfilt_exe = shutil.which('c++filt')
|
_cppfilt_exe = shutil.which("c++filt")
|
||||||
|
|
||||||
|
|
||||||
def demangle_symbol(symbol):
|
def demangle_symbol(symbol):
|
||||||
@ -73,35 +73,37 @@ def demangle_symbol(symbol):
|
|||||||
|
|
||||||
|
|
||||||
def is_elf(filename):
|
def is_elf(filename):
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, "rb") as f:
|
||||||
magic_bytes = f.read(4)
|
magic_bytes = f.read(4)
|
||||||
return magic_bytes == b'\x7fELF'
|
return magic_bytes == b"\x7fELF"
|
||||||
|
|
||||||
|
|
||||||
def is_mach_o(filename):
|
def is_mach_o(filename):
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, "rb") as f:
|
||||||
magic_bytes = f.read(4)
|
magic_bytes = f.read(4)
|
||||||
return magic_bytes in [
|
return magic_bytes in [
|
||||||
b'\xfe\xed\xfa\xce', # MH_MAGIC
|
b"\xfe\xed\xfa\xce", # MH_MAGIC
|
||||||
b'\xce\xfa\xed\xfe', # MH_CIGAM
|
b"\xce\xfa\xed\xfe", # MH_CIGAM
|
||||||
b'\xfe\xed\xfa\xcf', # MH_MAGIC_64
|
b"\xfe\xed\xfa\xcf", # MH_MAGIC_64
|
||||||
b'\xcf\xfa\xed\xfe', # MH_CIGAM_64
|
b"\xcf\xfa\xed\xfe", # MH_CIGAM_64
|
||||||
b'\xca\xfe\xba\xbe', # FAT_MAGIC
|
b"\xca\xfe\xba\xbe", # FAT_MAGIC
|
||||||
b'\xbe\xba\xfe\xca' # FAT_CIGAM
|
b"\xbe\xba\xfe\xca", # FAT_CIGAM
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def is_xcoff_or_big_ar(filename):
|
def is_xcoff_or_big_ar(filename):
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, "rb") as f:
|
||||||
magic_bytes = f.read(7)
|
magic_bytes = f.read(7)
|
||||||
return magic_bytes[:4] in [
|
return (
|
||||||
b'\x01DF', # XCOFF32
|
magic_bytes[:4] in [b"\x01DF", b"\x01F7"] # XCOFF32 # XCOFF64
|
||||||
b'\x01F7' # XCOFF64
|
or magic_bytes == b"<bigaf>"
|
||||||
] or magic_bytes == b'<bigaf>'
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_library_file(filename):
|
def is_library_file(filename):
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == "darwin":
|
||||||
return is_mach_o(filename)
|
return is_mach_o(filename)
|
||||||
elif sys.platform.startswith('aix'):
|
elif sys.platform.startswith("aix"):
|
||||||
return is_xcoff_or_big_ar(filename)
|
return is_xcoff_or_big_ar(filename)
|
||||||
else:
|
else:
|
||||||
return is_elf(filename)
|
return is_elf(filename)
|
||||||
@ -109,169 +111,167 @@ def is_library_file(filename):
|
|||||||
|
|
||||||
def extract_or_load(filename):
|
def extract_or_load(filename):
|
||||||
import libcxx.sym_check.extract
|
import libcxx.sym_check.extract
|
||||||
|
|
||||||
if is_library_file(filename):
|
if is_library_file(filename):
|
||||||
return libcxx.sym_check.extract.extract_symbols(filename)
|
return libcxx.sym_check.extract.extract_symbols(filename)
|
||||||
return read_syms_from_file(filename)
|
return read_syms_from_file(filename)
|
||||||
|
|
||||||
|
|
||||||
def adjust_mangled_name(name):
|
def adjust_mangled_name(name):
|
||||||
if not name.startswith('__Z'):
|
if not name.startswith("__Z"):
|
||||||
return name
|
return name
|
||||||
return name[1:]
|
return name[1:]
|
||||||
|
|
||||||
new_delete_std_symbols = [
|
|
||||||
'_Znam',
|
new_delete_std_symbols = ["_Znam", "_Znwm", "_ZdaPv", "_ZdaPvm", "_ZdlPv", "_ZdlPvm"]
|
||||||
'_Znwm',
|
|
||||||
'_ZdaPv',
|
|
||||||
'_ZdaPvm',
|
|
||||||
'_ZdlPv',
|
|
||||||
'_ZdlPvm'
|
|
||||||
]
|
|
||||||
|
|
||||||
cxxabi_symbols = [
|
cxxabi_symbols = [
|
||||||
'___dynamic_cast',
|
"___dynamic_cast",
|
||||||
'___gxx_personality_v0',
|
"___gxx_personality_v0",
|
||||||
'_ZTIDi',
|
"_ZTIDi",
|
||||||
'_ZTIDn',
|
"_ZTIDn",
|
||||||
'_ZTIDs',
|
"_ZTIDs",
|
||||||
'_ZTIPDi',
|
"_ZTIPDi",
|
||||||
'_ZTIPDn',
|
"_ZTIPDn",
|
||||||
'_ZTIPDs',
|
"_ZTIPDs",
|
||||||
'_ZTIPKDi',
|
"_ZTIPKDi",
|
||||||
'_ZTIPKDn',
|
"_ZTIPKDn",
|
||||||
'_ZTIPKDs',
|
"_ZTIPKDs",
|
||||||
'_ZTIPKa',
|
"_ZTIPKa",
|
||||||
'_ZTIPKb',
|
"_ZTIPKb",
|
||||||
'_ZTIPKc',
|
"_ZTIPKc",
|
||||||
'_ZTIPKd',
|
"_ZTIPKd",
|
||||||
'_ZTIPKe',
|
"_ZTIPKe",
|
||||||
'_ZTIPKf',
|
"_ZTIPKf",
|
||||||
'_ZTIPKh',
|
"_ZTIPKh",
|
||||||
'_ZTIPKi',
|
"_ZTIPKi",
|
||||||
'_ZTIPKj',
|
"_ZTIPKj",
|
||||||
'_ZTIPKl',
|
"_ZTIPKl",
|
||||||
'_ZTIPKm',
|
"_ZTIPKm",
|
||||||
'_ZTIPKs',
|
"_ZTIPKs",
|
||||||
'_ZTIPKt',
|
"_ZTIPKt",
|
||||||
'_ZTIPKv',
|
"_ZTIPKv",
|
||||||
'_ZTIPKw',
|
"_ZTIPKw",
|
||||||
'_ZTIPKx',
|
"_ZTIPKx",
|
||||||
'_ZTIPKy',
|
"_ZTIPKy",
|
||||||
'_ZTIPa',
|
"_ZTIPa",
|
||||||
'_ZTIPb',
|
"_ZTIPb",
|
||||||
'_ZTIPc',
|
"_ZTIPc",
|
||||||
'_ZTIPd',
|
"_ZTIPd",
|
||||||
'_ZTIPe',
|
"_ZTIPe",
|
||||||
'_ZTIPf',
|
"_ZTIPf",
|
||||||
'_ZTIPh',
|
"_ZTIPh",
|
||||||
'_ZTIPi',
|
"_ZTIPi",
|
||||||
'_ZTIPj',
|
"_ZTIPj",
|
||||||
'_ZTIPl',
|
"_ZTIPl",
|
||||||
'_ZTIPm',
|
"_ZTIPm",
|
||||||
'_ZTIPs',
|
"_ZTIPs",
|
||||||
'_ZTIPt',
|
"_ZTIPt",
|
||||||
'_ZTIPv',
|
"_ZTIPv",
|
||||||
'_ZTIPw',
|
"_ZTIPw",
|
||||||
'_ZTIPx',
|
"_ZTIPx",
|
||||||
'_ZTIPy',
|
"_ZTIPy",
|
||||||
'_ZTIa',
|
"_ZTIa",
|
||||||
'_ZTIb',
|
"_ZTIb",
|
||||||
'_ZTIc',
|
"_ZTIc",
|
||||||
'_ZTId',
|
"_ZTId",
|
||||||
'_ZTIe',
|
"_ZTIe",
|
||||||
'_ZTIf',
|
"_ZTIf",
|
||||||
'_ZTIh',
|
"_ZTIh",
|
||||||
'_ZTIi',
|
"_ZTIi",
|
||||||
'_ZTIj',
|
"_ZTIj",
|
||||||
'_ZTIl',
|
"_ZTIl",
|
||||||
'_ZTIm',
|
"_ZTIm",
|
||||||
'_ZTIs',
|
"_ZTIs",
|
||||||
'_ZTIt',
|
"_ZTIt",
|
||||||
'_ZTIv',
|
"_ZTIv",
|
||||||
'_ZTIw',
|
"_ZTIw",
|
||||||
'_ZTIx',
|
"_ZTIx",
|
||||||
'_ZTIy',
|
"_ZTIy",
|
||||||
'_ZTSDi',
|
"_ZTSDi",
|
||||||
'_ZTSDn',
|
"_ZTSDn",
|
||||||
'_ZTSDs',
|
"_ZTSDs",
|
||||||
'_ZTSPDi',
|
"_ZTSPDi",
|
||||||
'_ZTSPDn',
|
"_ZTSPDn",
|
||||||
'_ZTSPDs',
|
"_ZTSPDs",
|
||||||
'_ZTSPKDi',
|
"_ZTSPKDi",
|
||||||
'_ZTSPKDn',
|
"_ZTSPKDn",
|
||||||
'_ZTSPKDs',
|
"_ZTSPKDs",
|
||||||
'_ZTSPKa',
|
"_ZTSPKa",
|
||||||
'_ZTSPKb',
|
"_ZTSPKb",
|
||||||
'_ZTSPKc',
|
"_ZTSPKc",
|
||||||
'_ZTSPKd',
|
"_ZTSPKd",
|
||||||
'_ZTSPKe',
|
"_ZTSPKe",
|
||||||
'_ZTSPKf',
|
"_ZTSPKf",
|
||||||
'_ZTSPKh',
|
"_ZTSPKh",
|
||||||
'_ZTSPKi',
|
"_ZTSPKi",
|
||||||
'_ZTSPKj',
|
"_ZTSPKj",
|
||||||
'_ZTSPKl',
|
"_ZTSPKl",
|
||||||
'_ZTSPKm',
|
"_ZTSPKm",
|
||||||
'_ZTSPKs',
|
"_ZTSPKs",
|
||||||
'_ZTSPKt',
|
"_ZTSPKt",
|
||||||
'_ZTSPKv',
|
"_ZTSPKv",
|
||||||
'_ZTSPKw',
|
"_ZTSPKw",
|
||||||
'_ZTSPKx',
|
"_ZTSPKx",
|
||||||
'_ZTSPKy',
|
"_ZTSPKy",
|
||||||
'_ZTSPa',
|
"_ZTSPa",
|
||||||
'_ZTSPb',
|
"_ZTSPb",
|
||||||
'_ZTSPc',
|
"_ZTSPc",
|
||||||
'_ZTSPd',
|
"_ZTSPd",
|
||||||
'_ZTSPe',
|
"_ZTSPe",
|
||||||
'_ZTSPf',
|
"_ZTSPf",
|
||||||
'_ZTSPh',
|
"_ZTSPh",
|
||||||
'_ZTSPi',
|
"_ZTSPi",
|
||||||
'_ZTSPj',
|
"_ZTSPj",
|
||||||
'_ZTSPl',
|
"_ZTSPl",
|
||||||
'_ZTSPm',
|
"_ZTSPm",
|
||||||
'_ZTSPs',
|
"_ZTSPs",
|
||||||
'_ZTSPt',
|
"_ZTSPt",
|
||||||
'_ZTSPv',
|
"_ZTSPv",
|
||||||
'_ZTSPw',
|
"_ZTSPw",
|
||||||
'_ZTSPx',
|
"_ZTSPx",
|
||||||
'_ZTSPy',
|
"_ZTSPy",
|
||||||
'_ZTSa',
|
"_ZTSa",
|
||||||
'_ZTSb',
|
"_ZTSb",
|
||||||
'_ZTSc',
|
"_ZTSc",
|
||||||
'_ZTSd',
|
"_ZTSd",
|
||||||
'_ZTSe',
|
"_ZTSe",
|
||||||
'_ZTSf',
|
"_ZTSf",
|
||||||
'_ZTSh',
|
"_ZTSh",
|
||||||
'_ZTSi',
|
"_ZTSi",
|
||||||
'_ZTSj',
|
"_ZTSj",
|
||||||
'_ZTSl',
|
"_ZTSl",
|
||||||
'_ZTSm',
|
"_ZTSm",
|
||||||
'_ZTSs',
|
"_ZTSs",
|
||||||
'_ZTSt',
|
"_ZTSt",
|
||||||
'_ZTSv',
|
"_ZTSv",
|
||||||
'_ZTSw',
|
"_ZTSw",
|
||||||
'_ZTSx',
|
"_ZTSx",
|
||||||
'_ZTSy'
|
"_ZTSy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def is_stdlib_symbol_name(name, sym):
|
def is_stdlib_symbol_name(name, sym):
|
||||||
name = adjust_mangled_name(name)
|
name = adjust_mangled_name(name)
|
||||||
if re.search("@GLIBC|@GCC", name):
|
if re.search("@GLIBC|@GCC", name):
|
||||||
# Only when symbol is defined do we consider it ours
|
# Only when symbol is defined do we consider it ours
|
||||||
return sym['is_defined']
|
return sym["is_defined"]
|
||||||
if re.search('(St[0-9])|(__cxa)|(__cxxabi)', name):
|
if re.search("(St[0-9])|(__cxa)|(__cxxabi)", name):
|
||||||
return True
|
return True
|
||||||
if name in new_delete_std_symbols:
|
if name in new_delete_std_symbols:
|
||||||
return True
|
return True
|
||||||
if name in cxxabi_symbols:
|
if name in cxxabi_symbols:
|
||||||
return True
|
return True
|
||||||
if name.startswith('_Z'):
|
if name.startswith("_Z"):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def filter_stdlib_symbols(syms):
|
def filter_stdlib_symbols(syms):
|
||||||
stdlib_symbols = []
|
stdlib_symbols = []
|
||||||
other_symbols = []
|
other_symbols = []
|
||||||
for s in syms:
|
for s in syms:
|
||||||
canon_name = adjust_mangled_name(s['name'])
|
canon_name = adjust_mangled_name(s["name"])
|
||||||
if not is_stdlib_symbol_name(canon_name, s):
|
if not is_stdlib_symbol_name(canon_name, s):
|
||||||
other_symbols += [s]
|
other_symbols += [s]
|
||||||
else:
|
else:
|
||||||
|
@ -1,49 +1,55 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def _getSubstitution(substitution, config):
|
def _getSubstitution(substitution, config):
|
||||||
for (orig, replacement) in config.substitutions:
|
for (orig, replacement) in config.substitutions:
|
||||||
if orig == substitution:
|
if orig == substitution:
|
||||||
return replacement
|
return replacement
|
||||||
raise ValueError('Substitution {} is not in the config.'.format(substitution))
|
raise ValueError("Substitution {} is not in the config.".format(substitution))
|
||||||
|
|
||||||
|
|
||||||
def configure(parameters, features, config, lit_config):
|
def configure(parameters, features, config, lit_config):
|
||||||
note = lambda s: lit_config.note("({}) {}".format(config.name, s))
|
note = lambda s: lit_config.note("({}) {}".format(config.name, s))
|
||||||
config.environment = dict(os.environ)
|
config.environment = dict(os.environ)
|
||||||
|
|
||||||
# Apply the actions supplied by parameters to the configuration first, since
|
# Apply the actions supplied by parameters to the configuration first, since
|
||||||
# parameters are things that we request explicitly and which might influence
|
# parameters are things that we request explicitly and which might influence
|
||||||
# what features are implicitly made available next.
|
# what features are implicitly made available next.
|
||||||
for param in parameters:
|
for param in parameters:
|
||||||
actions = param.getActions(config, lit_config.params)
|
actions = param.getActions(config, lit_config.params)
|
||||||
for action in actions:
|
for action in actions:
|
||||||
action.applyTo(config)
|
action.applyTo(config)
|
||||||
if lit_config.debug:
|
if lit_config.debug:
|
||||||
note("Applied '{}' as a result of parameter '{}'".format(
|
note(
|
||||||
action.pretty(config, lit_config.params),
|
"Applied '{}' as a result of parameter '{}'".format(
|
||||||
param.pretty(config, lit_config.params)))
|
action.pretty(config, lit_config.params),
|
||||||
|
param.pretty(config, lit_config.params),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Then, apply the automatically-detected features.
|
# Then, apply the automatically-detected features.
|
||||||
for feature in features:
|
for feature in features:
|
||||||
actions = feature.getActions(config)
|
actions = feature.getActions(config)
|
||||||
for action in actions:
|
for action in actions:
|
||||||
action.applyTo(config)
|
action.applyTo(config)
|
||||||
if lit_config.debug:
|
if lit_config.debug:
|
||||||
note("Applied '{}' as a result of implicitly detected feature '{}'".format(
|
note(
|
||||||
action.pretty(config, lit_config.params),
|
"Applied '{}' as a result of implicitly detected feature '{}'".format(
|
||||||
feature.pretty(config)))
|
action.pretty(config, lit_config.params), feature.pretty(config)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Print the basic substitutions
|
# Print the basic substitutions
|
||||||
for sub in ('%{cxx}', '%{flags}', '%{compile_flags}', '%{link_flags}', '%{exec}'):
|
for sub in ("%{cxx}", "%{flags}", "%{compile_flags}", "%{link_flags}", "%{exec}"):
|
||||||
note("Using {} substitution: '{}'".format(sub, _getSubstitution(sub, config)))
|
note("Using {} substitution: '{}'".format(sub, _getSubstitution(sub, config)))
|
||||||
|
|
||||||
# Print all available features
|
# Print all available features
|
||||||
note("All available features: {}".format(', '.join(config.available_features)))
|
note("All available features: {}".format(", ".join(config.available_features)))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,10 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
from libcxx.test.dsl import *
|
from libcxx.test.dsl import *
|
||||||
from lit.BooleanExpression import BooleanExpression
|
from lit.BooleanExpression import BooleanExpression
|
||||||
@ -13,107 +13,176 @@ import shutil
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
_isClang = lambda cfg: '__clang__' in compilerMacros(cfg) and '__apple_build_version__' not in compilerMacros(cfg)
|
_isClang = lambda cfg: "__clang__" in compilerMacros(
|
||||||
_isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg)
|
cfg
|
||||||
_isGCC = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg)
|
) and "__apple_build_version__" not in compilerMacros(cfg)
|
||||||
_isMSVC = lambda cfg: '_MSC_VER' in compilerMacros(cfg)
|
_isAppleClang = lambda cfg: "__apple_build_version__" in compilerMacros(cfg)
|
||||||
_msvcVersion = lambda cfg: (int(compilerMacros(cfg)['_MSC_VER']) // 100, int(compilerMacros(cfg)['_MSC_VER']) % 100)
|
_isGCC = lambda cfg: "__GNUC__" in compilerMacros(
|
||||||
|
cfg
|
||||||
|
) and "__clang__" not in compilerMacros(cfg)
|
||||||
|
_isMSVC = lambda cfg: "_MSC_VER" in compilerMacros(cfg)
|
||||||
|
_msvcVersion = lambda cfg: (
|
||||||
|
int(compilerMacros(cfg)["_MSC_VER"]) // 100,
|
||||||
|
int(compilerMacros(cfg)["_MSC_VER"]) % 100,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _getSuitableClangTidy(cfg):
|
def _getSuitableClangTidy(cfg):
|
||||||
try:
|
try:
|
||||||
# If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests.
|
# If we didn't build the libcxx-tidy plugin via CMake, we can't run the clang-tidy tests.
|
||||||
if runScriptExitCode(cfg, ['stat %{test-tools}/clang_tidy_checks/libcxx-tidy.plugin']) != 0:
|
if (
|
||||||
return None
|
runScriptExitCode(
|
||||||
|
cfg, ["stat %{test-tools}/clang_tidy_checks/libcxx-tidy.plugin"]
|
||||||
|
)
|
||||||
|
!= 0
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
# TODO This should be the last stable release.
|
# TODO This should be the last stable release.
|
||||||
# LLVM RELEASE bump to latest stable version
|
# LLVM RELEASE bump to latest stable version
|
||||||
if runScriptExitCode(cfg, ['clang-tidy-16 --version']) == 0:
|
if runScriptExitCode(cfg, ["clang-tidy-16 --version"]) == 0:
|
||||||
return 'clang-tidy-16'
|
return "clang-tidy-16"
|
||||||
|
|
||||||
# LLVM RELEASE bump version
|
# LLVM RELEASE bump version
|
||||||
if int(re.search('[0-9]+', commandOutput(cfg, ['clang-tidy --version'])).group()) >= 16:
|
if (
|
||||||
return 'clang-tidy'
|
int(
|
||||||
|
re.search(
|
||||||
|
"[0-9]+", commandOutput(cfg, ["clang-tidy --version"])
|
||||||
|
).group()
|
||||||
|
)
|
||||||
|
>= 16
|
||||||
|
):
|
||||||
|
return "clang-tidy"
|
||||||
|
|
||||||
|
except ConfigurationRuntimeError:
|
||||||
|
return None
|
||||||
|
|
||||||
except ConfigurationRuntimeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
DEFAULT_FEATURES = [
|
DEFAULT_FEATURES = [
|
||||||
Feature(name='thread-safety',
|
Feature(
|
||||||
when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'),
|
name="thread-safety",
|
||||||
actions=[AddCompileFlag('-Werror=thread-safety')]),
|
when=lambda cfg: hasCompileFlag(cfg, "-Werror=thread-safety"),
|
||||||
|
actions=[AddCompileFlag("-Werror=thread-safety")],
|
||||||
Feature(name='diagnose-if-support',
|
),
|
||||||
when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'),
|
Feature(
|
||||||
actions=[AddCompileFlag('-Wuser-defined-warnings')]),
|
name="diagnose-if-support",
|
||||||
|
when=lambda cfg: hasCompileFlag(cfg, "-Wuser-defined-warnings"),
|
||||||
# Tests to validate whether the compiler has a way to set the maximum number
|
actions=[AddCompileFlag("-Wuser-defined-warnings")],
|
||||||
# of steps during constant evaluation. Since the flag differs per compiler
|
),
|
||||||
# store the "valid" flag as a feature. This allows passing the proper compile
|
# Tests to validate whether the compiler has a way to set the maximum number
|
||||||
# flag to the compiler:
|
# of steps during constant evaluation. Since the flag differs per compiler
|
||||||
# // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678
|
# store the "valid" flag as a feature. This allows passing the proper compile
|
||||||
# // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678
|
# flag to the compiler:
|
||||||
Feature(name='has-fconstexpr-steps',
|
# // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12345678
|
||||||
when=lambda cfg: hasCompileFlag(cfg, '-fconstexpr-steps=1')),
|
# // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12345678
|
||||||
|
Feature(
|
||||||
Feature(name='has-fconstexpr-ops-limit',
|
name="has-fconstexpr-steps",
|
||||||
when=lambda cfg: hasCompileFlag(cfg, '-fconstexpr-ops-limit=1')),
|
when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-steps=1"),
|
||||||
|
),
|
||||||
Feature(name='has-fblocks', when=lambda cfg: hasCompileFlag(cfg, '-fblocks')),
|
Feature(
|
||||||
Feature(name='-fsized-deallocation', when=lambda cfg: hasCompileFlag(cfg, '-fsized-deallocation')),
|
name="has-fconstexpr-ops-limit",
|
||||||
Feature(name='-faligned-allocation', when=lambda cfg: hasCompileFlag(cfg, '-faligned-allocation')),
|
when=lambda cfg: hasCompileFlag(cfg, "-fconstexpr-ops-limit=1"),
|
||||||
Feature(name='fdelayed-template-parsing', when=lambda cfg: hasCompileFlag(cfg, '-fdelayed-template-parsing')),
|
),
|
||||||
Feature(name='libcpp-no-coroutines', when=lambda cfg: featureTestMacros(cfg).get('__cpp_impl_coroutine', 0) < 201902),
|
Feature(name="has-fblocks", when=lambda cfg: hasCompileFlag(cfg, "-fblocks")),
|
||||||
Feature(name='has-fobjc-arc', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and
|
Feature(
|
||||||
sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms.
|
name="-fsized-deallocation",
|
||||||
Feature(name='objective-c++', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')),
|
when=lambda cfg: hasCompileFlag(cfg, "-fsized-deallocation"),
|
||||||
Feature(name='verify-support', when=lambda cfg: hasCompileFlag(cfg, '-Xclang -verify-ignore-unexpected')),
|
),
|
||||||
|
Feature(
|
||||||
Feature(name='non-lockfree-atomics',
|
name="-faligned-allocation",
|
||||||
when=lambda cfg: sourceBuilds(cfg, """
|
when=lambda cfg: hasCompileFlag(cfg, "-faligned-allocation"),
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="fdelayed-template-parsing",
|
||||||
|
when=lambda cfg: hasCompileFlag(cfg, "-fdelayed-template-parsing"),
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="libcpp-no-coroutines",
|
||||||
|
when=lambda cfg: featureTestMacros(cfg).get("__cpp_impl_coroutine", 0) < 201902,
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="has-fobjc-arc",
|
||||||
|
when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc")
|
||||||
|
and sys.platform.lower().strip() == "darwin",
|
||||||
|
), # TODO: this doesn't handle cross-compiling to Apple platforms.
|
||||||
|
Feature(
|
||||||
|
name="objective-c++",
|
||||||
|
when=lambda cfg: hasCompileFlag(cfg, "-xobjective-c++ -fobjc-arc"),
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="verify-support",
|
||||||
|
when=lambda cfg: hasCompileFlag(cfg, "-Xclang -verify-ignore-unexpected"),
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="non-lockfree-atomics",
|
||||||
|
when=lambda cfg: sourceBuilds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
struct Large { int storage[100]; };
|
struct Large { int storage[100]; };
|
||||||
std::atomic<Large> x;
|
std::atomic<Large> x;
|
||||||
int main(int, char**) { (void)x.load(); return 0; }
|
int main(int, char**) { (void)x.load(); return 0; }
|
||||||
""")),
|
""",
|
||||||
# TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree()
|
),
|
||||||
# on all supported platforms.
|
),
|
||||||
Feature(name='is-lockfree-runtime-function',
|
# TODO: Remove this feature once compiler-rt includes __atomic_is_lockfree()
|
||||||
when=lambda cfg: sourceBuilds(cfg, """
|
# on all supported platforms.
|
||||||
|
Feature(
|
||||||
|
name="is-lockfree-runtime-function",
|
||||||
|
when=lambda cfg: sourceBuilds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
struct Large { int storage[100]; };
|
struct Large { int storage[100]; };
|
||||||
std::atomic<Large> x;
|
std::atomic<Large> x;
|
||||||
int main(int, char**) { return x.is_lock_free(); }
|
int main(int, char**) { return x.is_lock_free(); }
|
||||||
""")),
|
""",
|
||||||
|
),
|
||||||
# Some tests rely on creating shared libraries which link in the C++ Standard Library. In some
|
),
|
||||||
# cases, this doesn't work (e.g. if the library was built as a static archive and wasn't compiled
|
# Some tests rely on creating shared libraries which link in the C++ Standard Library. In some
|
||||||
# as position independent). This feature informs the test suite of whether it's possible to create
|
# cases, this doesn't work (e.g. if the library was built as a static archive and wasn't compiled
|
||||||
# a shared library in a shell test by using the '-shared' compiler flag.
|
# as position independent). This feature informs the test suite of whether it's possible to create
|
||||||
#
|
# a shared library in a shell test by using the '-shared' compiler flag.
|
||||||
# Note: To implement this check properly, we need to make sure that we use something inside the
|
#
|
||||||
# compiled library, not only in the headers. It should be safe to assume that all implementations
|
# Note: To implement this check properly, we need to make sure that we use something inside the
|
||||||
# define `operator new` in the compiled library.
|
# compiled library, not only in the headers. It should be safe to assume that all implementations
|
||||||
Feature(name='cant-build-shared-library',
|
# define `operator new` in the compiled library.
|
||||||
when=lambda cfg: not sourceBuilds(cfg, """
|
Feature(
|
||||||
|
name="cant-build-shared-library",
|
||||||
|
when=lambda cfg: not sourceBuilds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
void f() { new int(3); }
|
void f() { new int(3); }
|
||||||
""", ['-shared'])),
|
""",
|
||||||
|
["-shared"],
|
||||||
# Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0):
|
),
|
||||||
# https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678
|
),
|
||||||
Feature(name='win32-broken-utf8-wchar-ctype',
|
# Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.20348.0):
|
||||||
when=lambda cfg: not '_LIBCPP_HAS_NO_LOCALIZATION' in compilerMacros(cfg) and '_WIN32' in compilerMacros(cfg) and not programSucceeds(cfg, """
|
# https://developercommunity.visualstudio.com/t/utf-8-locales-break-ctype-functions-for-wchar-type/1653678
|
||||||
|
Feature(
|
||||||
|
name="win32-broken-utf8-wchar-ctype",
|
||||||
|
when=lambda cfg: not "_LIBCPP_HAS_NO_LOCALIZATION" in compilerMacros(cfg)
|
||||||
|
and "_WIN32" in compilerMacros(cfg)
|
||||||
|
and not programSucceeds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
setlocale(LC_ALL, "en_US.UTF-8");
|
setlocale(LC_ALL, "en_US.UTF-8");
|
||||||
return towlower(L'\\xDA') != L'\\xFA';
|
return towlower(L'\\xDA') != L'\\xFA';
|
||||||
}
|
}
|
||||||
""")),
|
""",
|
||||||
|
),
|
||||||
# Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0).
|
),
|
||||||
# https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837
|
# Check for a Windows UCRT bug (fixed in UCRT/Windows 10.0.19041.0).
|
||||||
Feature(name='win32-broken-printf-g-precision',
|
# https://developercommunity.visualstudio.com/t/printf-formatting-with-g-outputs-too/1660837
|
||||||
when=lambda cfg: '_WIN32' in compilerMacros(cfg) and not programSucceeds(cfg, """
|
Feature(
|
||||||
|
name="win32-broken-printf-g-precision",
|
||||||
|
when=lambda cfg: "_WIN32" in compilerMacros(cfg)
|
||||||
|
and not programSucceeds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
@ -121,70 +190,126 @@ DEFAULT_FEATURES = [
|
|||||||
snprintf(buf, sizeof(buf), "%#.*g", 0, 0.0);
|
snprintf(buf, sizeof(buf), "%#.*g", 0, 0.0);
|
||||||
return strcmp(buf, "0.");
|
return strcmp(buf, "0.");
|
||||||
}
|
}
|
||||||
""")),
|
""",
|
||||||
|
),
|
||||||
# Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had
|
),
|
||||||
# mon_decimal_point == ".", which our tests don't handle.
|
# Check for Glibc < 2.27, where the ru_RU.UTF-8 locale had
|
||||||
Feature(name='glibc-old-ru_RU-decimal-point',
|
# mon_decimal_point == ".", which our tests don't handle.
|
||||||
when=lambda cfg: not '_LIBCPP_HAS_NO_LOCALIZATION' in compilerMacros(cfg) and not programSucceeds(cfg, """
|
Feature(
|
||||||
|
name="glibc-old-ru_RU-decimal-point",
|
||||||
|
when=lambda cfg: not "_LIBCPP_HAS_NO_LOCALIZATION" in compilerMacros(cfg)
|
||||||
|
and not programSucceeds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
setlocale(LC_ALL, "ru_RU.UTF-8");
|
setlocale(LC_ALL, "ru_RU.UTF-8");
|
||||||
return strcmp(localeconv()->mon_decimal_point, ",");
|
return strcmp(localeconv()->mon_decimal_point, ",");
|
||||||
}
|
}
|
||||||
""")),
|
""",
|
||||||
|
),
|
||||||
Feature(name='has-unix-headers',
|
),
|
||||||
when=lambda cfg: sourceBuilds(cfg, """
|
Feature(
|
||||||
|
name="has-unix-headers",
|
||||||
|
when=lambda cfg: sourceBuilds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
""")),
|
""",
|
||||||
|
),
|
||||||
# Whether Bash can run on the executor.
|
),
|
||||||
# This is not always the case, for example when running on embedded systems.
|
# Whether Bash can run on the executor.
|
||||||
#
|
# This is not always the case, for example when running on embedded systems.
|
||||||
# For the corner case of bash existing, but it being missing in the path
|
#
|
||||||
# set in %{exec} as "--env PATH=one-single-dir", the executor does find
|
# For the corner case of bash existing, but it being missing in the path
|
||||||
# and executes bash, but bash then can't find any other common shell
|
# set in %{exec} as "--env PATH=one-single-dir", the executor does find
|
||||||
# utilities. Test executing "bash -c 'bash --version'" to see if bash
|
# and executes bash, but bash then can't find any other common shell
|
||||||
# manages to find binaries to execute.
|
# utilities. Test executing "bash -c 'bash --version'" to see if bash
|
||||||
Feature(name='executor-has-no-bash',
|
# manages to find binaries to execute.
|
||||||
when=lambda cfg: runScriptExitCode(cfg, ['%{exec} bash -c \'bash --version\'']) != 0),
|
Feature(
|
||||||
Feature(name='has-clang-tidy',
|
name="executor-has-no-bash",
|
||||||
when=lambda cfg: _getSuitableClangTidy(cfg) is not None,
|
when=lambda cfg: runScriptExitCode(cfg, ["%{exec} bash -c 'bash --version'"])
|
||||||
actions=[AddSubstitution('%{clang-tidy}', lambda cfg: _getSuitableClangTidy(cfg))]),
|
!= 0,
|
||||||
|
),
|
||||||
Feature(name='apple-clang', when=_isAppleClang),
|
Feature(
|
||||||
Feature(name=lambda cfg: 'apple-clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isAppleClang),
|
name="has-clang-tidy",
|
||||||
Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)), when=_isAppleClang),
|
when=lambda cfg: _getSuitableClangTidy(cfg) is not None,
|
||||||
Feature(name=lambda cfg: 'apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isAppleClang),
|
actions=[
|
||||||
|
AddSubstitution("%{clang-tidy}", lambda cfg: _getSuitableClangTidy(cfg))
|
||||||
Feature(name='clang', when=_isClang),
|
],
|
||||||
Feature(name=lambda cfg: 'clang-{__clang_major__}'.format(**compilerMacros(cfg)), when=_isClang),
|
),
|
||||||
Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}'.format(**compilerMacros(cfg)), when=_isClang),
|
Feature(name="apple-clang", when=_isAppleClang),
|
||||||
Feature(name=lambda cfg: 'clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}'.format(**compilerMacros(cfg)), when=_isClang),
|
Feature(
|
||||||
|
name=lambda cfg: "apple-clang-{__clang_major__}".format(**compilerMacros(cfg)),
|
||||||
# Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings
|
when=_isAppleClang,
|
||||||
# on GCC or spurious diagnostics are issued.
|
),
|
||||||
#
|
Feature(
|
||||||
# TODO:
|
name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}".format(
|
||||||
# - Enable -Wplacement-new with GCC.
|
**compilerMacros(cfg)
|
||||||
# - Enable -Wclass-memaccess with GCC.
|
),
|
||||||
Feature(name='gcc', when=_isGCC,
|
when=_isAppleClang,
|
||||||
actions=[AddCompileFlag('-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS'),
|
),
|
||||||
AddCompileFlag('-Wno-placement-new'),
|
Feature(
|
||||||
AddCompileFlag('-Wno-class-memaccess')]),
|
name=lambda cfg: "apple-clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(
|
||||||
Feature(name=lambda cfg: 'gcc-{__GNUC__}'.format(**compilerMacros(cfg)), when=_isGCC),
|
**compilerMacros(cfg)
|
||||||
Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}'.format(**compilerMacros(cfg)), when=_isGCC),
|
),
|
||||||
Feature(name=lambda cfg: 'gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}'.format(**compilerMacros(cfg)), when=_isGCC),
|
when=_isAppleClang,
|
||||||
|
),
|
||||||
Feature(name='msvc', when=_isMSVC),
|
Feature(name="clang", when=_isClang),
|
||||||
Feature(name=lambda cfg: 'msvc-{}'.format(*_msvcVersion(cfg)), when=_isMSVC),
|
Feature(
|
||||||
Feature(name=lambda cfg: 'msvc-{}.{}'.format(*_msvcVersion(cfg)), when=_isMSVC),
|
name=lambda cfg: "clang-{__clang_major__}".format(**compilerMacros(cfg)),
|
||||||
|
when=_isClang,
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}".format(
|
||||||
|
**compilerMacros(cfg)
|
||||||
|
),
|
||||||
|
when=_isClang,
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name=lambda cfg: "clang-{__clang_major__}.{__clang_minor__}.{__clang_patchlevel__}".format(
|
||||||
|
**compilerMacros(cfg)
|
||||||
|
),
|
||||||
|
when=_isClang,
|
||||||
|
),
|
||||||
|
# Note: Due to a GCC bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104760), we must disable deprecation warnings
|
||||||
|
# on GCC or spurious diagnostics are issued.
|
||||||
|
#
|
||||||
|
# TODO:
|
||||||
|
# - Enable -Wplacement-new with GCC.
|
||||||
|
# - Enable -Wclass-memaccess with GCC.
|
||||||
|
Feature(
|
||||||
|
name="gcc",
|
||||||
|
when=_isGCC,
|
||||||
|
actions=[
|
||||||
|
AddCompileFlag("-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS"),
|
||||||
|
AddCompileFlag("-Wno-placement-new"),
|
||||||
|
AddCompileFlag("-Wno-class-memaccess"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name=lambda cfg: "gcc-{__GNUC__}".format(**compilerMacros(cfg)), when=_isGCC
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}".format(
|
||||||
|
**compilerMacros(cfg)
|
||||||
|
),
|
||||||
|
when=_isGCC,
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name=lambda cfg: "gcc-{__GNUC__}.{__GNUC_MINOR__}.{__GNUC_PATCHLEVEL__}".format(
|
||||||
|
**compilerMacros(cfg)
|
||||||
|
),
|
||||||
|
when=_isGCC,
|
||||||
|
),
|
||||||
|
Feature(name="msvc", when=_isMSVC),
|
||||||
|
Feature(name=lambda cfg: "msvc-{}".format(*_msvcVersion(cfg)), when=_isMSVC),
|
||||||
|
Feature(name=lambda cfg: "msvc-{}.{}".format(*_msvcVersion(cfg)), when=_isMSVC),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Deduce and add the test features that that are implied by the #defines in
|
# Deduce and add the test features that that are implied by the #defines in
|
||||||
@ -198,54 +323,70 @@ DEFAULT_FEATURES = [
|
|||||||
# Note that features that are more strongly tied to libc++ are named libcpp-foo,
|
# Note that features that are more strongly tied to libc++ are named libcpp-foo,
|
||||||
# while features that are more general in nature are not prefixed with 'libcpp-'.
|
# while features that are more general in nature are not prefixed with 'libcpp-'.
|
||||||
macros = {
|
macros = {
|
||||||
'_LIBCPP_HAS_NO_MONOTONIC_CLOCK': 'no-monotonic-clock',
|
"_LIBCPP_HAS_NO_MONOTONIC_CLOCK": "no-monotonic-clock",
|
||||||
'_LIBCPP_HAS_NO_THREADS': 'no-threads',
|
"_LIBCPP_HAS_NO_THREADS": "no-threads",
|
||||||
'_LIBCPP_HAS_THREAD_API_EXTERNAL': 'libcpp-has-thread-api-external',
|
"_LIBCPP_HAS_THREAD_API_EXTERNAL": "libcpp-has-thread-api-external",
|
||||||
'_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread',
|
"_LIBCPP_HAS_THREAD_API_PTHREAD": "libcpp-has-thread-api-pthread",
|
||||||
'_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime',
|
"_LIBCPP_NO_VCRUNTIME": "libcpp-no-vcruntime",
|
||||||
'_LIBCPP_ABI_VERSION': 'libcpp-abi-version',
|
"_LIBCPP_ABI_VERSION": "libcpp-abi-version",
|
||||||
'_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY': 'no-filesystem',
|
"_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY": "no-filesystem",
|
||||||
'_LIBCPP_HAS_NO_RANDOM_DEVICE': 'no-random-device',
|
"_LIBCPP_HAS_NO_RANDOM_DEVICE": "no-random-device",
|
||||||
'_LIBCPP_HAS_NO_LOCALIZATION': 'no-localization',
|
"_LIBCPP_HAS_NO_LOCALIZATION": "no-localization",
|
||||||
'_LIBCPP_HAS_NO_FSTREAM': 'no-fstream',
|
"_LIBCPP_HAS_NO_FSTREAM": "no-fstream",
|
||||||
'_LIBCPP_HAS_NO_WIDE_CHARACTERS': 'no-wide-characters',
|
"_LIBCPP_HAS_NO_WIDE_CHARACTERS": "no-wide-characters",
|
||||||
'_LIBCPP_HAS_NO_UNICODE': 'libcpp-has-no-unicode',
|
"_LIBCPP_HAS_NO_UNICODE": "libcpp-has-no-unicode",
|
||||||
'_LIBCPP_ENABLE_DEBUG_MODE': 'libcpp-has-debug-mode',
|
"_LIBCPP_ENABLE_DEBUG_MODE": "libcpp-has-debug-mode",
|
||||||
}
|
}
|
||||||
for macro, feature in macros.items():
|
for macro, feature in macros.items():
|
||||||
DEFAULT_FEATURES.append(
|
DEFAULT_FEATURES.append(
|
||||||
Feature(name=lambda cfg, m=macro, f=feature: f + ('={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''),
|
Feature(
|
||||||
when=lambda cfg, m=macro: m in compilerMacros(cfg))
|
name=lambda cfg, m=macro, f=feature: f
|
||||||
)
|
+ ("={}".format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ""),
|
||||||
|
when=lambda cfg, m=macro: m in compilerMacros(cfg),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Mapping from canonical locale names (used in the tests) to possible locale
|
# Mapping from canonical locale names (used in the tests) to possible locale
|
||||||
# names on various systems. Each locale is considered supported if any of the
|
# names on various systems. Each locale is considered supported if any of the
|
||||||
# alternative names is supported.
|
# alternative names is supported.
|
||||||
locales = {
|
locales = {
|
||||||
'en_US.UTF-8': ['en_US.UTF-8', 'en_US.utf8', 'English_United States.1252'],
|
"en_US.UTF-8": ["en_US.UTF-8", "en_US.utf8", "English_United States.1252"],
|
||||||
'fr_FR.UTF-8': ['fr_FR.UTF-8', 'fr_FR.utf8', 'French_France.1252'],
|
"fr_FR.UTF-8": ["fr_FR.UTF-8", "fr_FR.utf8", "French_France.1252"],
|
||||||
'ja_JP.UTF-8': ['ja_JP.UTF-8', 'ja_JP.utf8', 'Japanese_Japan.923'],
|
"ja_JP.UTF-8": ["ja_JP.UTF-8", "ja_JP.utf8", "Japanese_Japan.923"],
|
||||||
'ru_RU.UTF-8': ['ru_RU.UTF-8', 'ru_RU.utf8', 'Russian_Russia.1251'],
|
"ru_RU.UTF-8": ["ru_RU.UTF-8", "ru_RU.utf8", "Russian_Russia.1251"],
|
||||||
'zh_CN.UTF-8': ['zh_CN.UTF-8', 'zh_CN.utf8', 'Chinese_China.936'],
|
"zh_CN.UTF-8": ["zh_CN.UTF-8", "zh_CN.utf8", "Chinese_China.936"],
|
||||||
'fr_CA.ISO8859-1': ['fr_CA.ISO8859-1', 'French_Canada.1252'],
|
"fr_CA.ISO8859-1": ["fr_CA.ISO8859-1", "French_Canada.1252"],
|
||||||
'cs_CZ.ISO8859-2': ['cs_CZ.ISO8859-2', 'Czech_Czech Republic.1250']
|
"cs_CZ.ISO8859-2": ["cs_CZ.ISO8859-2", "Czech_Czech Republic.1250"],
|
||||||
}
|
}
|
||||||
for locale, alts in locales.items():
|
for locale, alts in locales.items():
|
||||||
# Note: Using alts directly in the lambda body here will bind it to the value at the
|
# Note: Using alts directly in the lambda body here will bind it to the value at the
|
||||||
# end of the loop. Assigning it to a default argument works around this issue.
|
# end of the loop. Assigning it to a default argument works around this issue.
|
||||||
DEFAULT_FEATURES.append(Feature(name='locale.{}'.format(locale),
|
DEFAULT_FEATURES.append(
|
||||||
when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts)))
|
Feature(
|
||||||
|
name="locale.{}".format(locale),
|
||||||
|
when=lambda cfg, alts=alts: hasAnyLocale(cfg, alts),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Add features representing the target platform name: darwin, linux, windows, etc...
|
# Add features representing the target platform name: darwin, linux, windows, etc...
|
||||||
DEFAULT_FEATURES += [
|
DEFAULT_FEATURES += [
|
||||||
Feature(name='darwin', when=lambda cfg: '__APPLE__' in compilerMacros(cfg)),
|
Feature(name="darwin", when=lambda cfg: "__APPLE__" in compilerMacros(cfg)),
|
||||||
Feature(name='windows', when=lambda cfg: '_WIN32' in compilerMacros(cfg)),
|
Feature(name="windows", when=lambda cfg: "_WIN32" in compilerMacros(cfg)),
|
||||||
Feature(name='windows-dll', when=lambda cfg: '_WIN32' in compilerMacros(cfg) and sourceBuilds(cfg, """
|
Feature(
|
||||||
|
name="windows-dll",
|
||||||
|
when=lambda cfg: "_WIN32" in compilerMacros(cfg)
|
||||||
|
and sourceBuilds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
int main(int, char**) { return 0; }
|
int main(int, char**) { return 0; }
|
||||||
""") and programSucceeds(cfg, """
|
""",
|
||||||
|
)
|
||||||
|
and programSucceeds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winnt.h>
|
#include <winnt.h>
|
||||||
@ -272,57 +413,76 @@ DEFAULT_FEATURES += [
|
|||||||
// loaded from a DLL.
|
// loaded from a DLL.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
"""), actions=[AddCompileFlag('-DTEST_WINDOWS_DLL')]),
|
""",
|
||||||
Feature(name='linux', when=lambda cfg: '__linux__' in compilerMacros(cfg)),
|
),
|
||||||
Feature(name='netbsd', when=lambda cfg: '__NetBSD__' in compilerMacros(cfg)),
|
actions=[AddCompileFlag("-DTEST_WINDOWS_DLL")],
|
||||||
Feature(name='freebsd', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)),
|
),
|
||||||
Feature(name='LIBCXX-FREEBSD-FIXME', when=lambda cfg: '__FreeBSD__' in compilerMacros(cfg)),
|
Feature(name="linux", when=lambda cfg: "__linux__" in compilerMacros(cfg)),
|
||||||
|
Feature(name="netbsd", when=lambda cfg: "__NetBSD__" in compilerMacros(cfg)),
|
||||||
|
Feature(name="freebsd", when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg)),
|
||||||
|
Feature(
|
||||||
|
name="LIBCXX-FREEBSD-FIXME",
|
||||||
|
when=lambda cfg: "__FreeBSD__" in compilerMacros(cfg),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add features representing the build host platform name.
|
# Add features representing the build host platform name.
|
||||||
# The build host could differ from the target platform for cross-compilation.
|
# The build host could differ from the target platform for cross-compilation.
|
||||||
DEFAULT_FEATURES += [
|
DEFAULT_FEATURES += [
|
||||||
Feature(name='buildhost={}'.format(sys.platform.lower().strip())),
|
Feature(name="buildhost={}".format(sys.platform.lower().strip())),
|
||||||
# sys.platform can often be represented by a "sub-system", such as 'win32', 'cygwin', 'mingw', freebsd13 & etc.
|
# sys.platform can often be represented by a "sub-system", such as 'win32', 'cygwin', 'mingw', freebsd13 & etc.
|
||||||
# We define a consolidated feature on a few platforms.
|
# We define a consolidated feature on a few platforms.
|
||||||
Feature(name='buildhost=windows', when=lambda cfg: platform.system().lower().startswith('windows')),
|
Feature(
|
||||||
Feature(name='buildhost=freebsd', when=lambda cfg: platform.system().lower().startswith('freebsd')),
|
name="buildhost=windows",
|
||||||
Feature(name='buildhost=aix', when=lambda cfg: platform.system().lower().startswith('aix'))
|
when=lambda cfg: platform.system().lower().startswith("windows"),
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="buildhost=freebsd",
|
||||||
|
when=lambda cfg: platform.system().lower().startswith("freebsd"),
|
||||||
|
),
|
||||||
|
Feature(
|
||||||
|
name="buildhost=aix",
|
||||||
|
when=lambda cfg: platform.system().lower().startswith("aix"),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Detect whether GDB is on the system, has Python scripting and supports
|
# Detect whether GDB is on the system, has Python scripting and supports
|
||||||
# adding breakpoint commands. If so add a substitution to access it.
|
# adding breakpoint commands. If so add a substitution to access it.
|
||||||
def check_gdb(cfg):
|
def check_gdb(cfg):
|
||||||
gdb_path = shutil.which('gdb')
|
gdb_path = shutil.which("gdb")
|
||||||
if gdb_path is None:
|
if gdb_path is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check that we can set breakpoint commands, which was added in 8.3.
|
# Check that we can set breakpoint commands, which was added in 8.3.
|
||||||
# Using the quit command here means that gdb itself exits, not just
|
# Using the quit command here means that gdb itself exits, not just
|
||||||
# the "python <...>" command.
|
# the "python <...>" command.
|
||||||
test_src = """\
|
test_src = """\
|
||||||
try:
|
try:
|
||||||
gdb.Breakpoint(\"main\").commands=\"foo\"
|
gdb.Breakpoint(\"main\").commands=\"foo\"
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
gdb.execute(\"quit 1\")
|
gdb.execute(\"quit 1\")
|
||||||
gdb.execute(\"quit\")"""
|
gdb.execute(\"quit\")"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
stdout = subprocess.check_output(
|
stdout = subprocess.check_output(
|
||||||
[gdb_path, "-ex", "python " + test_src, "--batch"],
|
[gdb_path, "-ex", "python " + test_src, "--batch"],
|
||||||
stderr=subprocess.DEVNULL, universal_newlines=True)
|
stderr=subprocess.DEVNULL,
|
||||||
except subprocess.CalledProcessError:
|
universal_newlines=True,
|
||||||
# We can't set breakpoint commands
|
)
|
||||||
return False
|
except subprocess.CalledProcessError:
|
||||||
|
# We can't set breakpoint commands
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check we actually ran the Python
|
||||||
|
return not "Python scripting is not supported" in stdout
|
||||||
|
|
||||||
# Check we actually ran the Python
|
|
||||||
return not "Python scripting is not supported" in stdout
|
|
||||||
|
|
||||||
DEFAULT_FEATURES += [
|
DEFAULT_FEATURES += [
|
||||||
Feature(name='host-has-gdb-with-python',
|
Feature(
|
||||||
when=check_gdb,
|
name="host-has-gdb-with-python",
|
||||||
actions=[AddSubstitution('%{gdb}', lambda cfg: shutil.which('gdb'))]
|
when=check_gdb,
|
||||||
)
|
actions=[AddSubstitution("%{gdb}", lambda cfg: shutil.which("gdb"))],
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Define features for back-deployment testing.
|
# Define features for back-deployment testing.
|
||||||
@ -339,56 +499,105 @@ DEFAULT_FEATURES += [
|
|||||||
# be achieved by creating a `.verify.cpp` test that checks for the right errors, and
|
# be achieved by creating a `.verify.cpp` test that checks for the right errors, and
|
||||||
# mark that test as requiring `stdlib=<vendor>-libc++ && target=<target>`.
|
# mark that test as requiring `stdlib=<vendor>-libc++ && target=<target>`.
|
||||||
DEFAULT_FEATURES += [
|
DEFAULT_FEATURES += [
|
||||||
# Tests that require std::to_chars(floating-point) in the built library
|
# Tests that require std::to_chars(floating-point) in the built library
|
||||||
Feature(name='availability-fp_to_chars-missing',
|
Feature(
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}', cfg.available_features)),
|
name="availability-fp_to_chars-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
# Tests that require https://wg21.link/P0482 support in the built library
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}",
|
||||||
Feature(name='availability-char8_t_support-missing',
|
cfg.available_features,
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}', cfg.available_features)),
|
),
|
||||||
|
),
|
||||||
# Tests that require __libcpp_verbose_abort support in the built library
|
# Tests that require https://wg21.link/P0482 support in the built library
|
||||||
Feature(name='availability-verbose_abort-missing',
|
Feature(
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}', cfg.available_features)),
|
name="availability-char8_t_support-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
# Tests that require std::bad_variant_access in the built library
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}",
|
||||||
Feature(name='availability-bad_variant_access-missing',
|
cfg.available_features,
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)),
|
),
|
||||||
|
),
|
||||||
# Tests that require std::bad_optional_access in the built library
|
# Tests that require __libcpp_verbose_abort support in the built library
|
||||||
Feature(name='availability-bad_optional_access-missing',
|
Feature(
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)),
|
name="availability-verbose_abort-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
# Tests that require std::bad_any_cast in the built library
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}",
|
||||||
Feature(name='availability-bad_any_cast-missing',
|
cfg.available_features,
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)),
|
),
|
||||||
|
),
|
||||||
# Tests that require std::pmr support in the built library
|
# Tests that require std::bad_variant_access in the built library
|
||||||
Feature(name='availability-pmr-missing',
|
Feature(
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}', cfg.available_features)),
|
name="availability-bad_variant_access-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
# Tests that require std::filesystem support in the built library
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}",
|
||||||
Feature(name='availability-filesystem-missing',
|
cfg.available_features,
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14)(.0)?}}', cfg.available_features)),
|
),
|
||||||
|
),
|
||||||
# Tests that require the C++20 synchronization library (P1135R6 implemented by https://llvm.org/D68480) in the built library
|
# Tests that require std::bad_optional_access in the built library
|
||||||
Feature(name='availability-synchronization_library-missing',
|
Feature(
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14|15)(.0)?}}', cfg.available_features)),
|
name="availability-bad_optional_access-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
# Tests that require support for std::shared_mutex and std::shared_timed_mutex in the built library
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}",
|
||||||
Feature(name='availability-shared_mutex-missing',
|
cfg.available_features,
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11)(.0)?}}', cfg.available_features)),
|
),
|
||||||
|
),
|
||||||
# Tests that require support for aligned allocation in the built library. This is about `operator new(..., std::align_val_t, ...)` specifically,
|
# Tests that require std::bad_any_cast in the built library
|
||||||
# not other forms of aligned allocation.
|
Feature(
|
||||||
Feature(name='availability-aligned_allocation-missing',
|
name="availability-bad_any_cast-missing",
|
||||||
when=lambda cfg: BooleanExpression.evaluate('stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}', cfg.available_features)),
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}",
|
||||||
# Tests that require 64-bit architecture
|
cfg.available_features,
|
||||||
Feature(name='32-bit-pointer',
|
),
|
||||||
when=lambda cfg: sourceBuilds(cfg, """
|
),
|
||||||
|
# Tests that require std::pmr support in the built library
|
||||||
|
Feature(
|
||||||
|
name="availability-pmr-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0)(.0)?}}",
|
||||||
|
cfg.available_features,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Tests that require std::filesystem support in the built library
|
||||||
|
Feature(
|
||||||
|
name="availability-filesystem-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14)(.0)?}}",
|
||||||
|
cfg.available_features,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Tests that require the C++20 synchronization library (P1135R6 implemented by https://llvm.org/D68480) in the built library
|
||||||
|
Feature(
|
||||||
|
name="availability-synchronization_library-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12|13|14|15)(.0)?}}",
|
||||||
|
cfg.available_features,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Tests that require support for std::shared_mutex and std::shared_timed_mutex in the built library
|
||||||
|
Feature(
|
||||||
|
name="availability-shared_mutex-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11)(.0)?}}",
|
||||||
|
cfg.available_features,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Tests that require support for aligned allocation in the built library. This is about `operator new(..., std::align_val_t, ...)` specifically,
|
||||||
|
# not other forms of aligned allocation.
|
||||||
|
Feature(
|
||||||
|
name="availability-aligned_allocation-missing",
|
||||||
|
when=lambda cfg: BooleanExpression.evaluate(
|
||||||
|
"stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{(9|10|11|12)(.0)?}}",
|
||||||
|
cfg.available_features,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Tests that require 64-bit architecture
|
||||||
|
Feature(
|
||||||
|
name="32-bit-pointer",
|
||||||
|
when=lambda cfg: sourceBuilds(
|
||||||
|
cfg,
|
||||||
|
"""
|
||||||
int main(int, char**) {
|
int main(int, char**) {
|
||||||
static_assert(sizeof(void *) == 4);
|
static_assert(sizeof(void *) == 4);
|
||||||
}
|
}
|
||||||
""")),
|
""",
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
import lit
|
import lit
|
||||||
import lit.formats
|
import lit.formats
|
||||||
@ -13,6 +13,7 @@ import pipes
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
def _getTempPaths(test):
|
def _getTempPaths(test):
|
||||||
"""
|
"""
|
||||||
Return the values to use for the %T and %t substitutions, respectively.
|
Return the values to use for the %T and %t substitutions, respectively.
|
||||||
@ -22,40 +23,45 @@ def _getTempPaths(test):
|
|||||||
"""
|
"""
|
||||||
tmpDir, _ = lit.TestRunner.getTempPaths(test)
|
tmpDir, _ = lit.TestRunner.getTempPaths(test)
|
||||||
_, testName = os.path.split(test.getExecPath())
|
_, testName = os.path.split(test.getExecPath())
|
||||||
tmpDir = os.path.join(tmpDir, testName + '.dir')
|
tmpDir = os.path.join(tmpDir, testName + ".dir")
|
||||||
tmpBase = os.path.join(tmpDir, 't')
|
tmpBase = os.path.join(tmpDir, "t")
|
||||||
return tmpDir, tmpBase
|
return tmpDir, tmpBase
|
||||||
|
|
||||||
|
|
||||||
def _checkBaseSubstitutions(substitutions):
|
def _checkBaseSubstitutions(substitutions):
|
||||||
substitutions = [s for (s, _) in substitutions]
|
substitutions = [s for (s, _) in substitutions]
|
||||||
for s in ['%{cxx}', '%{compile_flags}', '%{link_flags}', '%{flags}', '%{exec}']:
|
for s in ["%{cxx}", "%{compile_flags}", "%{link_flags}", "%{flags}", "%{exec}"]:
|
||||||
assert s in substitutions, "Required substitution {} was not provided".format(s)
|
assert s in substitutions, "Required substitution {} was not provided".format(s)
|
||||||
|
|
||||||
|
|
||||||
def _executeScriptInternal(test, litConfig, commands):
|
def _executeScriptInternal(test, litConfig, commands):
|
||||||
"""
|
"""
|
||||||
Returns (stdout, stderr, exitCode, timeoutInfo, parsedCommands)
|
Returns (stdout, stderr, exitCode, timeoutInfo, parsedCommands)
|
||||||
|
|
||||||
TODO: This really should be easier to access from Lit itself
|
TODO: This really should be easier to access from Lit itself
|
||||||
"""
|
"""
|
||||||
parsedCommands = parseScript(test, preamble=commands)
|
parsedCommands = parseScript(test, preamble=commands)
|
||||||
|
|
||||||
_, tmpBase = _getTempPaths(test)
|
_, tmpBase = _getTempPaths(test)
|
||||||
execDir = os.path.dirname(test.getExecPath())
|
execDir = os.path.dirname(test.getExecPath())
|
||||||
res = lit.TestRunner.executeScriptInternal(test, litConfig, tmpBase, parsedCommands, execDir)
|
res = lit.TestRunner.executeScriptInternal(
|
||||||
if isinstance(res, lit.Test.Result): # Handle failure to parse the Lit test
|
test, litConfig, tmpBase, parsedCommands, execDir
|
||||||
res = ('', res.output, 127, None)
|
)
|
||||||
(out, err, exitCode, timeoutInfo) = res
|
if isinstance(res, lit.Test.Result): # Handle failure to parse the Lit test
|
||||||
|
res = ("", res.output, 127, None)
|
||||||
|
(out, err, exitCode, timeoutInfo) = res
|
||||||
|
|
||||||
# TODO: As a temporary workaround until https://reviews.llvm.org/D81892 lands, manually
|
# TODO: As a temporary workaround until https://reviews.llvm.org/D81892 lands, manually
|
||||||
# split any stderr output that is included in stdout. It shouldn't be there, but
|
# split any stderr output that is included in stdout. It shouldn't be there, but
|
||||||
# the Lit internal shell conflates stderr and stdout.
|
# the Lit internal shell conflates stderr and stdout.
|
||||||
conflatedErrorOutput = re.search("(# command stderr:.+$)", out, flags=re.DOTALL)
|
conflatedErrorOutput = re.search("(# command stderr:.+$)", out, flags=re.DOTALL)
|
||||||
if conflatedErrorOutput:
|
if conflatedErrorOutput:
|
||||||
conflatedErrorOutput = conflatedErrorOutput.group(0)
|
conflatedErrorOutput = conflatedErrorOutput.group(0)
|
||||||
out = out[:-len(conflatedErrorOutput)]
|
out = out[: -len(conflatedErrorOutput)]
|
||||||
err += conflatedErrorOutput
|
err += conflatedErrorOutput
|
||||||
|
|
||||||
|
return (out, err, exitCode, timeoutInfo, parsedCommands)
|
||||||
|
|
||||||
return (out, err, exitCode, timeoutInfo, parsedCommands)
|
|
||||||
|
|
||||||
def parseScript(test, preamble):
|
def parseScript(test, preamble):
|
||||||
"""
|
"""
|
||||||
@ -78,32 +84,41 @@ def parseScript(test, preamble):
|
|||||||
|
|
||||||
# Check base substitutions and add the %{build} and %{run} convenience substitutions
|
# Check base substitutions and add the %{build} and %{run} convenience substitutions
|
||||||
_checkBaseSubstitutions(substitutions)
|
_checkBaseSubstitutions(substitutions)
|
||||||
substitutions.append(('%{build}', '%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe'))
|
substitutions.append(
|
||||||
substitutions.append(('%{run}', '%{exec} %t.exe'))
|
("%{build}", "%{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe")
|
||||||
|
)
|
||||||
|
substitutions.append(("%{run}", "%{exec} %t.exe"))
|
||||||
|
|
||||||
# Parse the test file, including custom directives
|
# Parse the test file, including custom directives
|
||||||
additionalCompileFlags = []
|
additionalCompileFlags = []
|
||||||
fileDependencies = []
|
fileDependencies = []
|
||||||
parsers = [
|
parsers = [
|
||||||
lit.TestRunner.IntegratedTestKeywordParser('FILE_DEPENDENCIES:',
|
lit.TestRunner.IntegratedTestKeywordParser(
|
||||||
lit.TestRunner.ParserKind.LIST,
|
"FILE_DEPENDENCIES:",
|
||||||
initial_value=fileDependencies),
|
lit.TestRunner.ParserKind.LIST,
|
||||||
lit.TestRunner.IntegratedTestKeywordParser('ADDITIONAL_COMPILE_FLAGS:',
|
initial_value=fileDependencies,
|
||||||
lit.TestRunner.ParserKind.LIST,
|
),
|
||||||
initial_value=additionalCompileFlags)
|
lit.TestRunner.IntegratedTestKeywordParser(
|
||||||
|
"ADDITIONAL_COMPILE_FLAGS:",
|
||||||
|
lit.TestRunner.ParserKind.LIST,
|
||||||
|
initial_value=additionalCompileFlags,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add conditional parsers for ADDITIONAL_COMPILE_FLAGS. This should be replaced by first
|
# Add conditional parsers for ADDITIONAL_COMPILE_FLAGS. This should be replaced by first
|
||||||
# class support for conditional keywords in Lit, which would allow evaluating arbitrary
|
# class support for conditional keywords in Lit, which would allow evaluating arbitrary
|
||||||
# Lit boolean expressions instead.
|
# Lit boolean expressions instead.
|
||||||
for feature in test.config.available_features:
|
for feature in test.config.available_features:
|
||||||
parser = lit.TestRunner.IntegratedTestKeywordParser('ADDITIONAL_COMPILE_FLAGS({}):'.format(feature),
|
parser = lit.TestRunner.IntegratedTestKeywordParser(
|
||||||
lit.TestRunner.ParserKind.LIST,
|
"ADDITIONAL_COMPILE_FLAGS({}):".format(feature),
|
||||||
initial_value=additionalCompileFlags)
|
lit.TestRunner.ParserKind.LIST,
|
||||||
|
initial_value=additionalCompileFlags,
|
||||||
|
)
|
||||||
parsers.append(parser)
|
parsers.append(parser)
|
||||||
|
|
||||||
scriptInTest = lit.TestRunner.parseIntegratedTestScript(test, additional_parsers=parsers,
|
scriptInTest = lit.TestRunner.parseIntegratedTestScript(
|
||||||
require_script=not preamble)
|
test, additional_parsers=parsers, require_script=not preamble
|
||||||
|
)
|
||||||
if isinstance(scriptInTest, lit.Test.Result):
|
if isinstance(scriptInTest, lit.Test.Result):
|
||||||
return scriptInTest
|
return scriptInTest
|
||||||
|
|
||||||
@ -113,17 +128,22 @@ def parseScript(test, preamble):
|
|||||||
# that file to the execution directory. Execute the copy from %S to allow
|
# that file to the execution directory. Execute the copy from %S to allow
|
||||||
# relative paths from the test directory.
|
# relative paths from the test directory.
|
||||||
for dep in fileDependencies:
|
for dep in fileDependencies:
|
||||||
script += ['%dbg(SETUP) cd %S && cp {} %T'.format(dep)]
|
script += ["%dbg(SETUP) cd %S && cp {} %T".format(dep)]
|
||||||
script += preamble
|
script += preamble
|
||||||
script += scriptInTest
|
script += scriptInTest
|
||||||
|
|
||||||
# Add compile flags specified with ADDITIONAL_COMPILE_FLAGS.
|
# Add compile flags specified with ADDITIONAL_COMPILE_FLAGS.
|
||||||
substitutions = [(s, x + ' ' + ' '.join(additionalCompileFlags)) if s == '%{compile_flags}'
|
substitutions = [
|
||||||
else (s, x) for (s, x) in substitutions]
|
(s, x + " " + " ".join(additionalCompileFlags))
|
||||||
|
if s == "%{compile_flags}"
|
||||||
|
else (s, x)
|
||||||
|
for (s, x) in substitutions
|
||||||
|
]
|
||||||
|
|
||||||
# Perform substitutions in the script itself.
|
# Perform substitutions in the script itself.
|
||||||
script = lit.TestRunner.applySubstitutions(script, substitutions,
|
script = lit.TestRunner.applySubstitutions(
|
||||||
recursion_limit=test.config.recursiveExpansionLimit)
|
script, substitutions, recursion_limit=test.config.recursiveExpansionLimit
|
||||||
|
)
|
||||||
|
|
||||||
return script
|
return script
|
||||||
|
|
||||||
@ -213,80 +233,100 @@ class CxxStandardLibraryTest(lit.formats.TestFormat):
|
|||||||
Equivalent to `%{exec} %t.exe`. This is intended to be used
|
Equivalent to `%{exec} %t.exe`. This is intended to be used
|
||||||
in conjunction with the %{build} substitution.
|
in conjunction with the %{build} substitution.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def getTestsInDirectory(self, testSuite, pathInSuite, litConfig, localConfig):
|
def getTestsInDirectory(self, testSuite, pathInSuite, litConfig, localConfig):
|
||||||
SUPPORTED_SUFFIXES = ['[.]pass[.]cpp$', '[.]pass[.]mm$',
|
SUPPORTED_SUFFIXES = [
|
||||||
'[.]compile[.]pass[.]cpp$', '[.]compile[.]pass[.]mm$',
|
"[.]pass[.]cpp$",
|
||||||
'[.]compile[.]fail[.]cpp$',
|
"[.]pass[.]mm$",
|
||||||
'[.]link[.]pass[.]cpp$', '[.]link[.]pass[.]mm$',
|
"[.]compile[.]pass[.]cpp$",
|
||||||
'[.]link[.]fail[.]cpp$',
|
"[.]compile[.]pass[.]mm$",
|
||||||
'[.]sh[.][^.]+$',
|
"[.]compile[.]fail[.]cpp$",
|
||||||
'[.]verify[.]cpp$',
|
"[.]link[.]pass[.]cpp$",
|
||||||
'[.]fail[.]cpp$']
|
"[.]link[.]pass[.]mm$",
|
||||||
|
"[.]link[.]fail[.]cpp$",
|
||||||
|
"[.]sh[.][^.]+$",
|
||||||
|
"[.]verify[.]cpp$",
|
||||||
|
"[.]fail[.]cpp$",
|
||||||
|
]
|
||||||
sourcePath = testSuite.getSourcePath(pathInSuite)
|
sourcePath = testSuite.getSourcePath(pathInSuite)
|
||||||
for filename in os.listdir(sourcePath):
|
for filename in os.listdir(sourcePath):
|
||||||
# Ignore dot files and excluded tests.
|
# Ignore dot files and excluded tests.
|
||||||
if filename.startswith('.') or filename in localConfig.excludes:
|
if filename.startswith(".") or filename in localConfig.excludes:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
filepath = os.path.join(sourcePath, filename)
|
filepath = os.path.join(sourcePath, filename)
|
||||||
if not os.path.isdir(filepath):
|
if not os.path.isdir(filepath):
|
||||||
if any([re.search(ext, filename) for ext in SUPPORTED_SUFFIXES]):
|
if any([re.search(ext, filename) for ext in SUPPORTED_SUFFIXES]):
|
||||||
yield lit.Test.Test(testSuite, pathInSuite + (filename,), localConfig)
|
yield lit.Test.Test(
|
||||||
|
testSuite, pathInSuite + (filename,), localConfig
|
||||||
|
)
|
||||||
|
|
||||||
def execute(self, test, litConfig):
|
def execute(self, test, litConfig):
|
||||||
VERIFY_FLAGS = '-Xclang -verify -Xclang -verify-ignore-unexpected=note -ferror-limit=0'
|
VERIFY_FLAGS = (
|
||||||
supportsVerify = 'verify-support' in test.config.available_features
|
"-Xclang -verify -Xclang -verify-ignore-unexpected=note -ferror-limit=0"
|
||||||
|
)
|
||||||
|
supportsVerify = "verify-support" in test.config.available_features
|
||||||
filename = test.path_in_suite[-1]
|
filename = test.path_in_suite[-1]
|
||||||
|
|
||||||
if re.search('[.]sh[.][^.]+$', filename):
|
if re.search("[.]sh[.][^.]+$", filename):
|
||||||
steps = [ ] # The steps are already in the script
|
steps = [] # The steps are already in the script
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
elif filename.endswith('.compile.pass.cpp') or filename.endswith('.compile.pass.mm'):
|
elif filename.endswith(".compile.pass.cpp") or filename.endswith(
|
||||||
|
".compile.pass.mm"
|
||||||
|
):
|
||||||
steps = [
|
steps = [
|
||||||
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -fsyntax-only"
|
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -fsyntax-only"
|
||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
elif filename.endswith('.compile.fail.cpp'):
|
elif filename.endswith(".compile.fail.cpp"):
|
||||||
steps = [
|
steps = [
|
||||||
"%dbg(COMPILED WITH) ! %{cxx} %s %{flags} %{compile_flags} -fsyntax-only"
|
"%dbg(COMPILED WITH) ! %{cxx} %s %{flags} %{compile_flags} -fsyntax-only"
|
||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
elif filename.endswith('.link.pass.cpp') or filename.endswith('.link.pass.mm'):
|
elif filename.endswith(".link.pass.cpp") or filename.endswith(".link.pass.mm"):
|
||||||
steps = [
|
steps = [
|
||||||
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe"
|
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe"
|
||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
elif filename.endswith('.link.fail.cpp'):
|
elif filename.endswith(".link.fail.cpp"):
|
||||||
steps = [
|
steps = [
|
||||||
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -c -o %t.o",
|
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} -c -o %t.o",
|
||||||
"%dbg(LINKED WITH) ! %{cxx} %t.o %{flags} %{link_flags} -o %t.exe"
|
"%dbg(LINKED WITH) ! %{cxx} %t.o %{flags} %{link_flags} -o %t.exe",
|
||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
elif filename.endswith('.verify.cpp'):
|
elif filename.endswith(".verify.cpp"):
|
||||||
if not supportsVerify:
|
if not supportsVerify:
|
||||||
return lit.Test.Result(lit.Test.UNSUPPORTED,
|
return lit.Test.Result(
|
||||||
"Test {} requires support for Clang-verify, which isn't supported by the compiler".format(test.getFullName()))
|
lit.Test.UNSUPPORTED,
|
||||||
|
"Test {} requires support for Clang-verify, which isn't supported by the compiler".format(
|
||||||
|
test.getFullName()
|
||||||
|
),
|
||||||
|
)
|
||||||
steps = [
|
steps = [
|
||||||
# Note: Use -Wno-error to make sure all diagnostics are not treated as errors,
|
# Note: Use -Wno-error to make sure all diagnostics are not treated as errors,
|
||||||
# which doesn't make sense for clang-verify tests.
|
# which doesn't make sense for clang-verify tests.
|
||||||
"%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format(VERIFY_FLAGS)
|
"%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format(
|
||||||
|
VERIFY_FLAGS
|
||||||
|
)
|
||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
# Make sure to check these ones last, since they will match other
|
# Make sure to check these ones last, since they will match other
|
||||||
# suffixes above too.
|
# suffixes above too.
|
||||||
elif filename.endswith('.pass.cpp') or filename.endswith('.pass.mm'):
|
elif filename.endswith(".pass.cpp") or filename.endswith(".pass.mm"):
|
||||||
steps = [
|
steps = [
|
||||||
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe",
|
"%dbg(COMPILED WITH) %{cxx} %s %{flags} %{compile_flags} %{link_flags} -o %t.exe",
|
||||||
"%dbg(EXECUTED AS) %{exec} %t.exe"
|
"%dbg(EXECUTED AS) %{exec} %t.exe",
|
||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
# This is like a .verify.cpp test when clang-verify is supported,
|
# This is like a .verify.cpp test when clang-verify is supported,
|
||||||
# otherwise it's like a .compile.fail.cpp test. This is only provided
|
# otherwise it's like a .compile.fail.cpp test. This is only provided
|
||||||
# for backwards compatibility with the test suite.
|
# for backwards compatibility with the test suite.
|
||||||
elif filename.endswith('.fail.cpp'):
|
elif filename.endswith(".fail.cpp"):
|
||||||
if supportsVerify:
|
if supportsVerify:
|
||||||
steps = [
|
steps = [
|
||||||
"%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format(VERIFY_FLAGS)
|
"%dbg(COMPILED WITH) %{{cxx}} %s %{{flags}} %{{compile_flags}} -fsyntax-only -Wno-error {}".format(
|
||||||
|
VERIFY_FLAGS
|
||||||
|
)
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
steps = [
|
steps = [
|
||||||
@ -294,19 +334,25 @@ class CxxStandardLibraryTest(lit.formats.TestFormat):
|
|||||||
]
|
]
|
||||||
return self._executeShTest(test, litConfig, steps)
|
return self._executeShTest(test, litConfig, steps)
|
||||||
else:
|
else:
|
||||||
return lit.Test.Result(lit.Test.UNRESOLVED, "Unknown test suffix for '{}'".format(filename))
|
return lit.Test.Result(
|
||||||
|
lit.Test.UNRESOLVED, "Unknown test suffix for '{}'".format(filename)
|
||||||
|
)
|
||||||
|
|
||||||
def _executeShTest(self, test, litConfig, steps):
|
def _executeShTest(self, test, litConfig, steps):
|
||||||
if test.config.unsupported:
|
if test.config.unsupported:
|
||||||
return lit.Test.Result(lit.Test.UNSUPPORTED, 'Test is unsupported')
|
return lit.Test.Result(lit.Test.UNSUPPORTED, "Test is unsupported")
|
||||||
|
|
||||||
script = parseScript(test, steps)
|
script = parseScript(test, steps)
|
||||||
if isinstance(script, lit.Test.Result):
|
if isinstance(script, lit.Test.Result):
|
||||||
return script
|
return script
|
||||||
|
|
||||||
if litConfig.noExecute:
|
if litConfig.noExecute:
|
||||||
return lit.Test.Result(lit.Test.XFAIL if test.isExpectedToFail() else lit.Test.PASS)
|
return lit.Test.Result(
|
||||||
|
lit.Test.XFAIL if test.isExpectedToFail() else lit.Test.PASS
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
_, tmpBase = _getTempPaths(test)
|
_, tmpBase = _getTempPaths(test)
|
||||||
useExternalSh = False
|
useExternalSh = False
|
||||||
return lit.TestRunner._runShTest(test, litConfig, useExternalSh, script, tmpBase)
|
return lit.TestRunner._runShTest(
|
||||||
|
test, litConfig, useExternalSh, script, tmpBase
|
||||||
|
)
|
||||||
|
@ -8,20 +8,21 @@ import lit.TestRunner
|
|||||||
import lit.util
|
import lit.util
|
||||||
from lit.formats.base import TestFormat
|
from lit.formats.base import TestFormat
|
||||||
|
|
||||||
kIsWindows = sys.platform in ['win32', 'cygwin']
|
kIsWindows = sys.platform in ["win32", "cygwin"]
|
||||||
|
|
||||||
|
|
||||||
class GoogleBenchmark(TestFormat):
|
class GoogleBenchmark(TestFormat):
|
||||||
def __init__(self, test_sub_dirs, test_suffix, benchmark_args=[]):
|
def __init__(self, test_sub_dirs, test_suffix, benchmark_args=[]):
|
||||||
self.benchmark_args = list(benchmark_args)
|
self.benchmark_args = list(benchmark_args)
|
||||||
self.test_sub_dirs = os.path.normcase(str(test_sub_dirs)).split(';')
|
self.test_sub_dirs = os.path.normcase(str(test_sub_dirs)).split(";")
|
||||||
|
|
||||||
# On Windows, assume tests will also end in '.exe'.
|
# On Windows, assume tests will also end in '.exe'.
|
||||||
exe_suffix = str(test_suffix)
|
exe_suffix = str(test_suffix)
|
||||||
if kIsWindows:
|
if kIsWindows:
|
||||||
exe_suffix += '.exe'
|
exe_suffix += ".exe"
|
||||||
|
|
||||||
# Also check for .py files for testing purposes.
|
# Also check for .py files for testing purposes.
|
||||||
self.test_suffixes = {exe_suffix, test_suffix + '.py'}
|
self.test_suffixes = {exe_suffix, test_suffix + ".py"}
|
||||||
|
|
||||||
def getBenchmarkTests(self, path, litConfig, localConfig):
|
def getBenchmarkTests(self, path, litConfig, localConfig):
|
||||||
"""getBenchmarkTests(path) - [name]
|
"""getBenchmarkTests(path) - [name]
|
||||||
@ -36,14 +37,14 @@ class GoogleBenchmark(TestFormat):
|
|||||||
# TODO: allow splitting tests according to the "benchmark family" so
|
# TODO: allow splitting tests according to the "benchmark family" so
|
||||||
# the output for a single family of tests all belongs to the same test
|
# the output for a single family of tests all belongs to the same test
|
||||||
# target.
|
# target.
|
||||||
list_test_cmd = [path, '--benchmark_list_tests']
|
list_test_cmd = [path, "--benchmark_list_tests"]
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(list_test_cmd,
|
output = subprocess.check_output(list_test_cmd, env=localConfig.environment)
|
||||||
env=localConfig.environment)
|
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
litConfig.warning(
|
litConfig.warning(
|
||||||
"unable to discover google-benchmarks in %r: %s. Process output: %s"
|
"unable to discover google-benchmarks in %r: %s. Process output: %s"
|
||||||
% (path, sys.exc_info()[1], exc.output))
|
% (path, sys.exc_info()[1], exc.output)
|
||||||
|
)
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
nested_tests = []
|
nested_tests = []
|
||||||
@ -53,69 +54,72 @@ class GoogleBenchmark(TestFormat):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
index = 0
|
index = 0
|
||||||
while ln[index*2:index*2+2] == ' ':
|
while ln[index * 2 : index * 2 + 2] == " ":
|
||||||
index += 1
|
index += 1
|
||||||
while len(nested_tests) > index:
|
while len(nested_tests) > index:
|
||||||
nested_tests.pop()
|
nested_tests.pop()
|
||||||
|
|
||||||
ln = ln[index*2:]
|
ln = ln[index * 2 :]
|
||||||
if ln.endswith('.'):
|
if ln.endswith("."):
|
||||||
nested_tests.append(ln)
|
nested_tests.append(ln)
|
||||||
elif any([name.startswith('DISABLED_')
|
elif any([name.startswith("DISABLED_") for name in nested_tests + [ln]]):
|
||||||
for name in nested_tests + [ln]]):
|
|
||||||
# Gtest will internally skip these tests. No need to launch a
|
# Gtest will internally skip these tests. No need to launch a
|
||||||
# child process for it.
|
# child process for it.
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
yield ''.join(nested_tests) + ln
|
yield "".join(nested_tests) + ln
|
||||||
|
|
||||||
def getTestsInDirectory(self, testSuite, path_in_suite,
|
def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
|
||||||
litConfig, localConfig):
|
|
||||||
source_path = testSuite.getSourcePath(path_in_suite)
|
source_path = testSuite.getSourcePath(path_in_suite)
|
||||||
for subdir in self.test_sub_dirs:
|
for subdir in self.test_sub_dirs:
|
||||||
dir_path = os.path.join(source_path, subdir)
|
dir_path = os.path.join(source_path, subdir)
|
||||||
if not os.path.isdir(dir_path):
|
if not os.path.isdir(dir_path):
|
||||||
continue
|
continue
|
||||||
for fn in lit.util.listdir_files(dir_path,
|
for fn in lit.util.listdir_files(dir_path, suffixes=self.test_suffixes):
|
||||||
suffixes=self.test_suffixes):
|
|
||||||
# Discover the tests in this executable.
|
# Discover the tests in this executable.
|
||||||
execpath = os.path.join(source_path, subdir, fn)
|
execpath = os.path.join(source_path, subdir, fn)
|
||||||
testnames = self.getBenchmarkTests(execpath, litConfig, localConfig)
|
testnames = self.getBenchmarkTests(execpath, litConfig, localConfig)
|
||||||
for testname in testnames:
|
for testname in testnames:
|
||||||
testPath = path_in_suite + (subdir, fn, testname)
|
testPath = path_in_suite + (subdir, fn, testname)
|
||||||
yield lit.Test.Test(testSuite, testPath, localConfig,
|
yield lit.Test.Test(
|
||||||
file_path=execpath)
|
testSuite, testPath, localConfig, file_path=execpath
|
||||||
|
)
|
||||||
|
|
||||||
def execute(self, test, litConfig):
|
def execute(self, test, litConfig):
|
||||||
testPath,testName = os.path.split(test.getSourcePath())
|
testPath, testName = os.path.split(test.getSourcePath())
|
||||||
while not os.path.exists(testPath):
|
while not os.path.exists(testPath):
|
||||||
# Handle GTest parametrized and typed tests, whose name includes
|
# Handle GTest parametrized and typed tests, whose name includes
|
||||||
# some '/'s.
|
# some '/'s.
|
||||||
testPath, namePrefix = os.path.split(testPath)
|
testPath, namePrefix = os.path.split(testPath)
|
||||||
testName = namePrefix + '/' + testName
|
testName = namePrefix + "/" + testName
|
||||||
|
|
||||||
cmd = [testPath, '--benchmark_filter=%s$' % testName ] + self.benchmark_args
|
cmd = [testPath, "--benchmark_filter=%s$" % testName] + self.benchmark_args
|
||||||
|
|
||||||
if litConfig.noExecute:
|
if litConfig.noExecute:
|
||||||
return lit.Test.PASS, ''
|
return lit.Test.PASS, ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out, err, exitCode = lit.util.executeCommand(
|
out, err, exitCode = lit.util.executeCommand(
|
||||||
cmd, env=test.config.environment,
|
cmd,
|
||||||
timeout=litConfig.maxIndividualTestTime)
|
env=test.config.environment,
|
||||||
|
timeout=litConfig.maxIndividualTestTime,
|
||||||
|
)
|
||||||
except lit.util.ExecuteCommandTimeoutException:
|
except lit.util.ExecuteCommandTimeoutException:
|
||||||
return (lit.Test.TIMEOUT,
|
return (
|
||||||
'Reached timeout of {} seconds'.format(
|
lit.Test.TIMEOUT,
|
||||||
litConfig.maxIndividualTestTime)
|
"Reached timeout of {} seconds".format(litConfig.maxIndividualTestTime),
|
||||||
)
|
)
|
||||||
|
|
||||||
if exitCode:
|
if exitCode:
|
||||||
return lit.Test.FAIL, ('exit code: %d\n' % exitCode) + out + err
|
return lit.Test.FAIL, ("exit code: %d\n" % exitCode) + out + err
|
||||||
|
|
||||||
passing_test_line = testName
|
passing_test_line = testName
|
||||||
if passing_test_line not in out:
|
if passing_test_line not in out:
|
||||||
msg = ('Unable to find %r in google benchmark output:\n\n%s%s' %
|
msg = "Unable to find %r in google benchmark output:\n\n%s%s" % (
|
||||||
(passing_test_line, out, err))
|
passing_test_line,
|
||||||
|
out,
|
||||||
|
err,
|
||||||
|
)
|
||||||
return lit.Test.UNRESOLVED, msg
|
return lit.Test.UNRESOLVED, msg
|
||||||
|
|
||||||
return lit.Test.PASS, err + out
|
return lit.Test.PASS, err + out
|
||||||
|
@ -1,126 +1,158 @@
|
|||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
from libcxx.test.dsl import *
|
from libcxx.test.dsl import *
|
||||||
from libcxx.test.features import _isMSVC
|
from libcxx.test.features import _isMSVC
|
||||||
import re
|
import re
|
||||||
|
|
||||||
_warningFlags = [
|
_warningFlags = [
|
||||||
'-Werror',
|
"-Werror",
|
||||||
'-Wall',
|
"-Wall",
|
||||||
'-Wctad-maybe-unsupported',
|
"-Wctad-maybe-unsupported",
|
||||||
'-Wextra',
|
"-Wextra",
|
||||||
'-Wshadow',
|
"-Wshadow",
|
||||||
'-Wundef',
|
"-Wundef",
|
||||||
'-Wunused-template',
|
"-Wunused-template",
|
||||||
'-Wno-unused-command-line-argument',
|
"-Wno-unused-command-line-argument",
|
||||||
'-Wno-attributes',
|
"-Wno-attributes",
|
||||||
'-Wno-pessimizing-move',
|
"-Wno-pessimizing-move",
|
||||||
'-Wno-c++11-extensions',
|
"-Wno-c++11-extensions",
|
||||||
'-Wno-noexcept-type',
|
"-Wno-noexcept-type",
|
||||||
'-Wno-aligned-allocation-unavailable',
|
"-Wno-aligned-allocation-unavailable",
|
||||||
'-Wno-atomic-alignment',
|
"-Wno-atomic-alignment",
|
||||||
|
# GCC warns about places where we might want to add sized allocation/deallocation
|
||||||
# GCC warns about places where we might want to add sized allocation/deallocation
|
# functions, but we know better what we're doing/testing in the test suite.
|
||||||
# functions, but we know better what we're doing/testing in the test suite.
|
"-Wno-sized-deallocation",
|
||||||
'-Wno-sized-deallocation',
|
# Turn off warnings about user-defined literals with reserved suffixes. Those are
|
||||||
|
# just noise since we are testing the Standard Library itself.
|
||||||
# Turn off warnings about user-defined literals with reserved suffixes. Those are
|
"-Wno-literal-suffix", # GCC
|
||||||
# just noise since we are testing the Standard Library itself.
|
"-Wno-user-defined-literals", # Clang
|
||||||
'-Wno-literal-suffix', # GCC
|
# GCC warns about this when TEST_IS_CONSTANT_EVALUATED is used on a non-constexpr
|
||||||
'-Wno-user-defined-literals', # Clang
|
# function. (This mostely happens in C++11 mode.)
|
||||||
|
# TODO(mordante) investigate a solution for this issue.
|
||||||
# GCC warns about this when TEST_IS_CONSTANT_EVALUATED is used on a non-constexpr
|
"-Wno-tautological-compare",
|
||||||
# function. (This mostely happens in C++11 mode.)
|
# -Wstringop-overread and -Wstringop-overflow seem to be a bit buggy currently
|
||||||
# TODO(mordante) investigate a solution for this issue.
|
"-Wno-stringop-overread",
|
||||||
'-Wno-tautological-compare',
|
"-Wno-stringop-overflow",
|
||||||
|
# These warnings should be enabled in order to support the MSVC
|
||||||
# -Wstringop-overread and -Wstringop-overflow seem to be a bit buggy currently
|
# team using the test suite; They enable the warnings below and
|
||||||
'-Wno-stringop-overread',
|
# expect the test suite to be clean.
|
||||||
'-Wno-stringop-overflow',
|
"-Wsign-compare",
|
||||||
|
"-Wunused-variable",
|
||||||
# These warnings should be enabled in order to support the MSVC
|
"-Wunused-parameter",
|
||||||
# team using the test suite; They enable the warnings below and
|
"-Wunreachable-code",
|
||||||
# expect the test suite to be clean.
|
"-Wno-unused-local-typedef",
|
||||||
'-Wsign-compare',
|
|
||||||
'-Wunused-variable',
|
|
||||||
'-Wunused-parameter',
|
|
||||||
'-Wunreachable-code',
|
|
||||||
'-Wno-unused-local-typedef',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
_allStandards = ['c++03', 'c++11', 'c++14', 'c++17', 'c++20', 'c++23', 'c++26']
|
_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26"]
|
||||||
|
|
||||||
|
|
||||||
def getStdFlag(cfg, std):
|
def getStdFlag(cfg, std):
|
||||||
fallbacks = {
|
fallbacks = {
|
||||||
'c++11': 'c++0x',
|
"c++11": "c++0x",
|
||||||
'c++14': 'c++1y',
|
"c++14": "c++1y",
|
||||||
'c++17': 'c++1z',
|
"c++17": "c++1z",
|
||||||
'c++20': 'c++2a',
|
"c++20": "c++2a",
|
||||||
'c++23': 'c++2b',
|
"c++23": "c++2b",
|
||||||
}
|
}
|
||||||
# TODO(LLVM-17) Remove this clang-tidy-16 work-around
|
# TODO(LLVM-17) Remove this clang-tidy-16 work-around
|
||||||
if std == 'c++23':
|
if std == "c++23":
|
||||||
std = 'c++2b'
|
std = "c++2b"
|
||||||
if hasCompileFlag(cfg, '-std='+std):
|
if hasCompileFlag(cfg, "-std=" + std):
|
||||||
return '-std='+std
|
return "-std=" + std
|
||||||
if std in fallbacks and hasCompileFlag(cfg, '-std='+fallbacks[std]):
|
if std in fallbacks and hasCompileFlag(cfg, "-std=" + fallbacks[std]):
|
||||||
return '-std='+fallbacks[std]
|
return "-std=" + fallbacks[std]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_PARAMETERS = [
|
DEFAULT_PARAMETERS = [
|
||||||
Parameter(name='target_triple', type=str,
|
Parameter(
|
||||||
help="The target triple to compile the test suite for. This must be "
|
name="target_triple",
|
||||||
"compatible with the target that the tests will be run on.",
|
type=str,
|
||||||
actions=lambda triple: filter(None, [
|
help="The target triple to compile the test suite for. This must be "
|
||||||
AddFeature('target={}'.format(triple)),
|
"compatible with the target that the tests will be run on.",
|
||||||
AddFlagIfSupported('--target={}'.format(triple)),
|
actions=lambda triple: filter(
|
||||||
AddSubstitution('%{triple}', triple)
|
None,
|
||||||
])),
|
[
|
||||||
|
AddFeature("target={}".format(triple)),
|
||||||
Parameter(name='std', choices=_allStandards, type=str,
|
AddFlagIfSupported("--target={}".format(triple)),
|
||||||
help="The version of the standard to compile the test suite with.",
|
AddSubstitution("%{triple}", triple),
|
||||||
default=lambda cfg: next(s for s in reversed(_allStandards) if getStdFlag(cfg, s)),
|
],
|
||||||
actions=lambda std: [
|
),
|
||||||
AddFeature(std),
|
),
|
||||||
AddSubstitution('%{cxx_std}', re.sub('\+','x', std)),
|
Parameter(
|
||||||
AddCompileFlag(lambda cfg: getStdFlag(cfg, std)),
|
name="std",
|
||||||
]),
|
choices=_allStandards,
|
||||||
|
type=str,
|
||||||
Parameter(name='enable_modules', choices=[True, False], type=bool, default=False,
|
help="The version of the standard to compile the test suite with.",
|
||||||
help="Whether to build the test suite with Clang modules enabled.",
|
default=lambda cfg: next(
|
||||||
actions=lambda modules: [
|
s for s in reversed(_allStandards) if getStdFlag(cfg, s)
|
||||||
AddFeature('modules-build'),
|
),
|
||||||
AddCompileFlag('-fmodules'),
|
actions=lambda std: [
|
||||||
AddCompileFlag('-fcxx-modules'), # AppleClang disregards -fmodules entirely when compiling C++. This enables modules for C++.
|
AddFeature(std),
|
||||||
] if modules else []),
|
AddSubstitution("%{cxx_std}", re.sub("\+", "x", std)),
|
||||||
|
AddCompileFlag(lambda cfg: getStdFlag(cfg, std)),
|
||||||
Parameter(name='enable_modules_lsv', choices=[True, False], type=bool, default=False,
|
],
|
||||||
help="Whether to enable Local Submodule Visibility in the Modules build.",
|
),
|
||||||
actions=lambda lsv: [
|
Parameter(
|
||||||
AddCompileFlag('-Xclang -fmodules-local-submodule-visibility'),
|
name="enable_modules",
|
||||||
] if lsv else []),
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
Parameter(name='enable_exceptions', choices=[True, False], type=bool, default=True,
|
default=False,
|
||||||
help="Whether to enable exceptions when compiling the test suite.",
|
help="Whether to build the test suite with Clang modules enabled.",
|
||||||
actions=lambda exceptions: [] if exceptions else [
|
actions=lambda modules: [
|
||||||
AddFeature('no-exceptions'),
|
AddFeature("modules-build"),
|
||||||
AddCompileFlag('-fno-exceptions')
|
AddCompileFlag("-fmodules"),
|
||||||
]),
|
AddCompileFlag(
|
||||||
|
"-fcxx-modules"
|
||||||
Parameter(name='enable_rtti', choices=[True, False], type=bool, default=True,
|
), # AppleClang disregards -fmodules entirely when compiling C++. This enables modules for C++.
|
||||||
help="Whether to enable RTTI when compiling the test suite.",
|
]
|
||||||
actions=lambda rtti: [] if rtti else [
|
if modules
|
||||||
AddFeature('no-rtti'),
|
else [],
|
||||||
AddCompileFlag('-fno-rtti')
|
),
|
||||||
]),
|
Parameter(
|
||||||
|
name="enable_modules_lsv",
|
||||||
Parameter(name='stdlib', choices=['llvm-libc++', 'apple-libc++', 'libstdc++', 'msvc'], type=str, default='llvm-libc++',
|
choices=[True, False],
|
||||||
help="""The C++ Standard Library implementation being tested.
|
type=bool,
|
||||||
|
default=False,
|
||||||
|
help="Whether to enable Local Submodule Visibility in the Modules build.",
|
||||||
|
actions=lambda lsv: [
|
||||||
|
AddCompileFlag("-Xclang -fmodules-local-submodule-visibility"),
|
||||||
|
]
|
||||||
|
if lsv
|
||||||
|
else [],
|
||||||
|
),
|
||||||
|
Parameter(
|
||||||
|
name="enable_exceptions",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
default=True,
|
||||||
|
help="Whether to enable exceptions when compiling the test suite.",
|
||||||
|
actions=lambda exceptions: []
|
||||||
|
if exceptions
|
||||||
|
else [AddFeature("no-exceptions"), AddCompileFlag("-fno-exceptions")],
|
||||||
|
),
|
||||||
|
Parameter(
|
||||||
|
name="enable_rtti",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
default=True,
|
||||||
|
help="Whether to enable RTTI when compiling the test suite.",
|
||||||
|
actions=lambda rtti: []
|
||||||
|
if rtti
|
||||||
|
else [AddFeature("no-rtti"), AddCompileFlag("-fno-rtti")],
|
||||||
|
),
|
||||||
|
Parameter(
|
||||||
|
name="stdlib",
|
||||||
|
choices=["llvm-libc++", "apple-libc++", "libstdc++", "msvc"],
|
||||||
|
type=str,
|
||||||
|
default="llvm-libc++",
|
||||||
|
help="""The C++ Standard Library implementation being tested.
|
||||||
|
|
||||||
Note that this parameter can also be used to encode different 'flavors' of the same
|
Note that this parameter can also be used to encode different 'flavors' of the same
|
||||||
standard library, such as libc++ as shipped by a different vendor, if it has different
|
standard library, such as libc++ as shipped by a different vendor, if it has different
|
||||||
@ -134,88 +166,148 @@ DEFAULT_PARAMETERS = [
|
|||||||
- libstdc++: The GNU C++ library typically shipped with GCC.
|
- libstdc++: The GNU C++ library typically shipped with GCC.
|
||||||
- msvc: The Microsoft implementation of the C++ Standard Library.
|
- msvc: The Microsoft implementation of the C++ Standard Library.
|
||||||
""",
|
""",
|
||||||
actions=lambda stdlib: filter(None, [
|
actions=lambda stdlib: filter(
|
||||||
AddFeature('stdlib={}'.format(stdlib)),
|
None,
|
||||||
# Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify
|
[
|
||||||
# the test suite.
|
AddFeature("stdlib={}".format(stdlib)),
|
||||||
AddFeature('stdlib=libc++') if re.match('.+-libc\+\+', stdlib) else None
|
# Also add an umbrella feature 'stdlib=libc++' for all flavors of libc++, to simplify
|
||||||
])),
|
# the test suite.
|
||||||
|
AddFeature("stdlib=libc++")
|
||||||
Parameter(name='enable_warnings', choices=[True, False], type=bool, default=True,
|
if re.match(".+-libc\+\+", stdlib)
|
||||||
help="Whether to enable warnings when compiling the test suite.",
|
else None,
|
||||||
actions=lambda warnings: [] if not warnings else
|
],
|
||||||
[AddOptionalWarningFlag(w) for w in _warningFlags] +
|
),
|
||||||
[AddCompileFlag('-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER')]
|
),
|
||||||
|
Parameter(
|
||||||
|
name="enable_warnings",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
default=True,
|
||||||
|
help="Whether to enable warnings when compiling the test suite.",
|
||||||
|
actions=lambda warnings: []
|
||||||
|
if not warnings
|
||||||
|
else [AddOptionalWarningFlag(w) for w in _warningFlags]
|
||||||
|
+ [AddCompileFlag("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER")],
|
||||||
|
),
|
||||||
|
Parameter(
|
||||||
|
name="use_sanitizer",
|
||||||
|
choices=[
|
||||||
|
"",
|
||||||
|
"Address",
|
||||||
|
"HWAddress",
|
||||||
|
"Undefined",
|
||||||
|
"Memory",
|
||||||
|
"MemoryWithOrigins",
|
||||||
|
"Thread",
|
||||||
|
"DataFlow",
|
||||||
|
"Leaks",
|
||||||
|
],
|
||||||
|
type=str,
|
||||||
|
default="",
|
||||||
|
help="An optional sanitizer to enable when building and running the test suite.",
|
||||||
|
actions=lambda sanitizer: filter(
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddFlag("-g -fno-omit-frame-pointer") if sanitizer else None,
|
||||||
|
AddFlag(
|
||||||
|
"-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all"
|
||||||
|
)
|
||||||
|
if sanitizer == "Undefined"
|
||||||
|
else None,
|
||||||
|
AddFeature("ubsan") if sanitizer == "Undefined" else None,
|
||||||
|
AddFlag("-fsanitize=address") if sanitizer == "Address" else None,
|
||||||
|
AddFeature("asan") if sanitizer == "Address" else None,
|
||||||
|
AddFlag("-fsanitize=hwaddress") if sanitizer == "HWAddress" else None,
|
||||||
|
AddFeature("hwasan") if sanitizer == "HWAddress" else None,
|
||||||
|
AddFlag("-fsanitize=memory")
|
||||||
|
if sanitizer in ["Memory", "MemoryWithOrigins"]
|
||||||
|
else None,
|
||||||
|
AddFeature("msan")
|
||||||
|
if sanitizer in ["Memory", "MemoryWithOrigins"]
|
||||||
|
else None,
|
||||||
|
AddFlag("-fsanitize-memory-track-origins")
|
||||||
|
if sanitizer == "MemoryWithOrigins"
|
||||||
|
else None,
|
||||||
|
AddFlag("-fsanitize=thread") if sanitizer == "Thread" else None,
|
||||||
|
AddFeature("tsan") if sanitizer == "Thread" else None,
|
||||||
|
AddFlag("-fsanitize=dataflow") if sanitizer == "DataFlow" else None,
|
||||||
|
AddFlag("-fsanitize=leaks") if sanitizer == "Leaks" else None,
|
||||||
|
AddFeature("sanitizer-new-delete")
|
||||||
|
if sanitizer
|
||||||
|
in ["Address", "HWAddress", "Memory", "MemoryWithOrigins", "Thread"]
|
||||||
|
else None,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Parameter(
|
||||||
|
name="enable_experimental",
|
||||||
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
|
default=True,
|
||||||
|
help="Whether to enable tests for experimental C++ Library features.",
|
||||||
|
actions=lambda experimental: [
|
||||||
|
# When linking in MSVC mode via the Clang driver, a -l<foo>
|
||||||
|
# maps to <foo>.lib, so we need to use -llibc++experimental here
|
||||||
|
# to make it link against the static libc++experimental.lib.
|
||||||
|
# We can't check for the feature 'msvc' in available_features
|
||||||
|
# as those features are added after processing parameters.
|
||||||
|
AddFeature("c++experimental"),
|
||||||
|
PrependLinkFlag(
|
||||||
|
lambda cfg: "-llibc++experimental"
|
||||||
|
if _isMSVC(cfg)
|
||||||
|
else "-lc++experimental"
|
||||||
),
|
),
|
||||||
|
AddCompileFlag("-D_LIBCPP_ENABLE_EXPERIMENTAL"),
|
||||||
Parameter(name='use_sanitizer', choices=['', 'Address', 'HWAddress', 'Undefined', 'Memory', 'MemoryWithOrigins', 'Thread', 'DataFlow', 'Leaks'], type=str, default='',
|
]
|
||||||
help="An optional sanitizer to enable when building and running the test suite.",
|
if experimental
|
||||||
actions=lambda sanitizer: filter(None, [
|
else [
|
||||||
AddFlag('-g -fno-omit-frame-pointer') if sanitizer else None,
|
AddFeature("libcpp-has-no-incomplete-pstl"),
|
||||||
|
],
|
||||||
AddFlag('-fsanitize=undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all') if sanitizer == 'Undefined' else None,
|
),
|
||||||
AddFeature('ubsan') if sanitizer == 'Undefined' else None,
|
Parameter(
|
||||||
|
name="long_tests",
|
||||||
AddFlag('-fsanitize=address') if sanitizer == 'Address' else None,
|
choices=[True, False],
|
||||||
AddFeature('asan') if sanitizer == 'Address' else None,
|
type=bool,
|
||||||
|
default=True,
|
||||||
AddFlag('-fsanitize=hwaddress') if sanitizer == 'HWAddress' else None,
|
help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.",
|
||||||
AddFeature('hwasan') if sanitizer == 'HWAddress' else None,
|
actions=lambda enabled: [] if not enabled else [AddFeature("long_tests")],
|
||||||
|
),
|
||||||
AddFlag('-fsanitize=memory') if sanitizer in ['Memory', 'MemoryWithOrigins'] else None,
|
Parameter(
|
||||||
AddFeature('msan') if sanitizer in ['Memory', 'MemoryWithOrigins'] else None,
|
name="enable_assertions",
|
||||||
AddFlag('-fsanitize-memory-track-origins') if sanitizer == 'MemoryWithOrigins' else None,
|
choices=[True, False],
|
||||||
|
type=bool,
|
||||||
AddFlag('-fsanitize=thread') if sanitizer == 'Thread' else None,
|
default=False,
|
||||||
AddFeature('tsan') if sanitizer == 'Thread' else None,
|
help="Whether to enable assertions when compiling the test suite. This is only meaningful when "
|
||||||
|
"running the tests against libc++.",
|
||||||
AddFlag('-fsanitize=dataflow') if sanitizer == 'DataFlow' else None,
|
actions=lambda assertions: [
|
||||||
AddFlag('-fsanitize=leaks') if sanitizer == 'Leaks' else None,
|
AddCompileFlag("-D_LIBCPP_ENABLE_ASSERTIONS=1"),
|
||||||
|
AddFeature("libcpp-has-assertions"),
|
||||||
AddFeature('sanitizer-new-delete') if sanitizer in ['Address', 'HWAddress', 'Memory', 'MemoryWithOrigins', 'Thread'] else None,
|
]
|
||||||
])),
|
if assertions
|
||||||
|
else [],
|
||||||
Parameter(name='enable_experimental', choices=[True, False], type=bool, default=True,
|
),
|
||||||
help="Whether to enable tests for experimental C++ Library features.",
|
Parameter(
|
||||||
actions=lambda experimental: [
|
name="additional_features",
|
||||||
# When linking in MSVC mode via the Clang driver, a -l<foo>
|
type=list,
|
||||||
# maps to <foo>.lib, so we need to use -llibc++experimental here
|
default=[],
|
||||||
# to make it link against the static libc++experimental.lib.
|
help="A comma-delimited list of additional features that will be enabled when running the tests. "
|
||||||
# We can't check for the feature 'msvc' in available_features
|
"This should be used sparingly since specifying ad-hoc features manually is error-prone and "
|
||||||
# as those features are added after processing parameters.
|
"brittle in the long run as changes are made to the test suite.",
|
||||||
AddFeature('c++experimental'),
|
actions=lambda features: [AddFeature(f) for f in features],
|
||||||
PrependLinkFlag(lambda cfg: '-llibc++experimental' if _isMSVC(cfg) else '-lc++experimental'),
|
),
|
||||||
AddCompileFlag('-D_LIBCPP_ENABLE_EXPERIMENTAL'),
|
Parameter(
|
||||||
] if experimental else [
|
name="enable_transitive_includes",
|
||||||
AddFeature('libcpp-has-no-incomplete-pstl'),
|
choices=[True, False],
|
||||||
]),
|
type=bool,
|
||||||
|
default=True,
|
||||||
Parameter(name='long_tests', choices=[True, False], type=bool, default=True,
|
help="Whether to enable backwards-compatibility transitive includes when running the tests. This "
|
||||||
help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.",
|
"is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between "
|
||||||
actions=lambda enabled: [] if not enabled else [
|
"points at which we bulk-remove transitive includes.",
|
||||||
AddFeature('long_tests')
|
actions=lambda enabled: []
|
||||||
]),
|
if enabled
|
||||||
|
else [
|
||||||
Parameter(name='enable_assertions', choices=[True, False], type=bool, default=False,
|
AddFeature("transitive-includes-disabled"),
|
||||||
help="Whether to enable assertions when compiling the test suite. This is only meaningful when "
|
AddCompileFlag("-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES"),
|
||||||
"running the tests against libc++.",
|
],
|
||||||
actions=lambda assertions: [
|
),
|
||||||
AddCompileFlag('-D_LIBCPP_ENABLE_ASSERTIONS=1'),
|
|
||||||
AddFeature('libcpp-has-assertions')
|
|
||||||
] if assertions else []),
|
|
||||||
|
|
||||||
Parameter(name='additional_features', type=list, default=[],
|
|
||||||
help="A comma-delimited list of additional features that will be enabled when running the tests. "
|
|
||||||
"This should be used sparingly since specifying ad-hoc features manually is error-prone and "
|
|
||||||
"brittle in the long run as changes are made to the test suite.",
|
|
||||||
actions=lambda features: [AddFeature(f) for f in features]),
|
|
||||||
|
|
||||||
Parameter(name='enable_transitive_includes', choices=[True, False], type=bool, default=True,
|
|
||||||
help="Whether to enable backwards-compatibility transitive includes when running the tests. This "
|
|
||||||
"is provided to ensure that the trimmed-down version of libc++ does not bit-rot in between "
|
|
||||||
"points at which we bulk-remove transitive includes.",
|
|
||||||
actions=lambda enabled: [] if enabled else [
|
|
||||||
AddFeature('transitive-includes-disabled'),
|
|
||||||
AddCompileFlag('-D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES')
|
|
||||||
]),
|
|
||||||
]
|
]
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
"""run.py is a utility for running a program.
|
"""run.py is a utility for running a program.
|
||||||
|
|
||||||
@ -21,10 +21,12 @@ import subprocess
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--execdir', type=str, required=True)
|
parser.add_argument("--execdir", type=str, required=True)
|
||||||
parser.add_argument('--codesign_identity', type=str, required=False, default=None)
|
parser.add_argument("--codesign_identity", type=str, required=False, default=None)
|
||||||
parser.add_argument('--env', type=str, nargs='*', required=False, default=[])
|
parser.add_argument("--env", type=str, nargs="*", required=False, default=[])
|
||||||
parser.add_argument('--prepend_env', type=str, nargs='*', required=False, default=[])
|
parser.add_argument(
|
||||||
|
"--prepend_env", type=str, nargs="*", required=False, default=[]
|
||||||
|
)
|
||||||
parser.add_argument("command", nargs=argparse.ONE_OR_MORE)
|
parser.add_argument("command", nargs=argparse.ONE_OR_MORE)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
commandLine = args.command
|
commandLine = args.command
|
||||||
@ -35,35 +37,37 @@ def main():
|
|||||||
# below. This allows us to do custom processing like codesigning test-executables.
|
# below. This allows us to do custom processing like codesigning test-executables.
|
||||||
# It's also possible for there to be no such executable, for example in the case
|
# It's also possible for there to be no such executable, for example in the case
|
||||||
# of a .sh.cpp test.
|
# of a .sh.cpp test.
|
||||||
isTestExe = lambda exe: exe.endswith('.tmp.exe') and os.path.exists(exe)
|
isTestExe = lambda exe: exe.endswith(".tmp.exe") and os.path.exists(exe)
|
||||||
|
|
||||||
# Do any necessary codesigning of test-executables found in the command line.
|
# Do any necessary codesigning of test-executables found in the command line.
|
||||||
if args.codesign_identity:
|
if args.codesign_identity:
|
||||||
for exe in filter(isTestExe, commandLine):
|
for exe in filter(isTestExe, commandLine):
|
||||||
subprocess.check_call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={})
|
subprocess.check_call(
|
||||||
|
["xcrun", "codesign", "-f", "-s", args.codesign_identity, exe], env={}
|
||||||
|
)
|
||||||
|
|
||||||
# Extract environment variables into a dictionary
|
# Extract environment variables into a dictionary
|
||||||
env = {k : v for (k, v) in map(lambda s: s.split('=', 1), args.env)}
|
env = {k: v for (k, v) in map(lambda s: s.split("=", 1), args.env)}
|
||||||
|
|
||||||
# Set environment variables where we prepend the given value to the
|
# Set environment variables where we prepend the given value to the
|
||||||
# existing environment variable.
|
# existing environment variable.
|
||||||
for (k, v) in map(lambda s: s.split('=', 1), args.prepend_env):
|
for (k, v) in map(lambda s: s.split("=", 1), args.prepend_env):
|
||||||
if k in os.environ:
|
if k in os.environ:
|
||||||
v = v + os.pathsep + os.environ[k]
|
v = v + os.pathsep + os.environ[k]
|
||||||
env[k] = v
|
env[k] = v
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == "Windows":
|
||||||
# Pass some extra variables through on Windows:
|
# Pass some extra variables through on Windows:
|
||||||
# COMSPEC is needed for running subprocesses via std::system().
|
# COMSPEC is needed for running subprocesses via std::system().
|
||||||
if 'COMSPEC' in os.environ:
|
if "COMSPEC" in os.environ:
|
||||||
env['COMSPEC'] = os.environ.get('COMSPEC')
|
env["COMSPEC"] = os.environ.get("COMSPEC")
|
||||||
# TEMP is needed for placing temp files in a sensible directory.
|
# TEMP is needed for placing temp files in a sensible directory.
|
||||||
if 'TEMP' in os.environ:
|
if "TEMP" in os.environ:
|
||||||
env['TEMP'] = os.environ.get('TEMP')
|
env["TEMP"] = os.environ.get("TEMP")
|
||||||
|
|
||||||
# Run the command line with the given environment in the execution directory.
|
# Run the command line with the given environment in the execution directory.
|
||||||
return subprocess.call(commandLine, cwd=args.execdir, env=env, shell=False)
|
return subprocess.call(commandLine, cwd=args.execdir, env=env, shell=False)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
exit(main())
|
exit(main())
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Runs an executable on a remote host.
|
Runs an executable on a remote host.
|
||||||
@ -25,37 +25,43 @@ import tempfile
|
|||||||
|
|
||||||
from shlex import quote as cmd_quote
|
from shlex import quote as cmd_quote
|
||||||
|
|
||||||
|
|
||||||
def ssh(args, command):
|
def ssh(args, command):
|
||||||
cmd = ['ssh', '-oBatchMode=yes']
|
cmd = ["ssh", "-oBatchMode=yes"]
|
||||||
if args.extra_ssh_args is not None:
|
if args.extra_ssh_args is not None:
|
||||||
cmd.extend(shlex.split(args.extra_ssh_args))
|
cmd.extend(shlex.split(args.extra_ssh_args))
|
||||||
return cmd + [args.host, command]
|
return cmd + [args.host, command]
|
||||||
|
|
||||||
|
|
||||||
def scp(args, src, dst):
|
def scp(args, src, dst):
|
||||||
cmd = ['scp', '-q', '-oBatchMode=yes']
|
cmd = ["scp", "-q", "-oBatchMode=yes"]
|
||||||
if args.extra_scp_args is not None:
|
if args.extra_scp_args is not None:
|
||||||
cmd.extend(shlex.split(args.extra_scp_args))
|
cmd.extend(shlex.split(args.extra_scp_args))
|
||||||
return cmd + [src, '{}:{}'.format(args.host, dst)]
|
return cmd + [src, "{}:{}".format(args.host, dst)]
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--host', type=str, required=True)
|
parser.add_argument("--host", type=str, required=True)
|
||||||
parser.add_argument('--execdir', type=str, required=True)
|
parser.add_argument("--execdir", type=str, required=True)
|
||||||
parser.add_argument('--tempdir', type=str, required=False, default='/tmp')
|
parser.add_argument("--tempdir", type=str, required=False, default="/tmp")
|
||||||
parser.add_argument('--extra-ssh-args', type=str, required=False)
|
parser.add_argument("--extra-ssh-args", type=str, required=False)
|
||||||
parser.add_argument('--extra-scp-args', type=str, required=False)
|
parser.add_argument("--extra-scp-args", type=str, required=False)
|
||||||
parser.add_argument('--codesign_identity', type=str, required=False, default=None)
|
parser.add_argument("--codesign_identity", type=str, required=False, default=None)
|
||||||
parser.add_argument('--env', type=str, nargs='*', required=False, default=[])
|
parser.add_argument("--env", type=str, nargs="*", required=False, default=[])
|
||||||
parser.add_argument('--prepend_env', type=str, nargs='*', required=False, default=[])
|
parser.add_argument(
|
||||||
|
"--prepend_env", type=str, nargs="*", required=False, default=[]
|
||||||
|
)
|
||||||
parser.add_argument("command", nargs=argparse.ONE_OR_MORE)
|
parser.add_argument("command", nargs=argparse.ONE_OR_MORE)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
commandLine = args.command
|
commandLine = args.command
|
||||||
|
|
||||||
# Create a temporary directory where the test will be run.
|
# Create a temporary directory where the test will be run.
|
||||||
# That is effectively the value of %T on the remote host.
|
# That is effectively the value of %T on the remote host.
|
||||||
tmp = subprocess.check_output(ssh(args, 'mktemp -d {}/libcxx.XXXXXXXXXX'.format(args.tempdir)), universal_newlines=True).strip()
|
tmp = subprocess.check_output(
|
||||||
|
ssh(args, "mktemp -d {}/libcxx.XXXXXXXXXX".format(args.tempdir)),
|
||||||
|
universal_newlines=True,
|
||||||
|
).strip()
|
||||||
|
|
||||||
# HACK:
|
# HACK:
|
||||||
# If an argument is a file that ends in `.tmp.exe`, assume it is the name
|
# If an argument is a file that ends in `.tmp.exe`, assume it is the name
|
||||||
@ -64,20 +70,23 @@ def main():
|
|||||||
# and changing their path when running on the remote host. It's also possible
|
# and changing their path when running on the remote host. It's also possible
|
||||||
# for there to be no such executable, for example in the case of a .sh.cpp
|
# for there to be no such executable, for example in the case of a .sh.cpp
|
||||||
# test.
|
# test.
|
||||||
isTestExe = lambda exe: exe.endswith('.tmp.exe') and os.path.exists(exe)
|
isTestExe = lambda exe: exe.endswith(".tmp.exe") and os.path.exists(exe)
|
||||||
pathOnRemote = lambda file: posixpath.join(tmp, os.path.basename(file))
|
pathOnRemote = lambda file: posixpath.join(tmp, os.path.basename(file))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Do any necessary codesigning of test-executables found in the command line.
|
# Do any necessary codesigning of test-executables found in the command line.
|
||||||
if args.codesign_identity:
|
if args.codesign_identity:
|
||||||
for exe in filter(isTestExe, commandLine):
|
for exe in filter(isTestExe, commandLine):
|
||||||
subprocess.check_call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={})
|
subprocess.check_call(
|
||||||
|
["xcrun", "codesign", "-f", "-s", args.codesign_identity, exe],
|
||||||
|
env={},
|
||||||
|
)
|
||||||
|
|
||||||
# tar up the execution directory (which contains everything that's needed
|
# tar up the execution directory (which contains everything that's needed
|
||||||
# to run the test), and copy the tarball over to the remote host.
|
# to run the test), and copy the tarball over to the remote host.
|
||||||
try:
|
try:
|
||||||
tmpTar = tempfile.NamedTemporaryFile(suffix='.tar', delete=False)
|
tmpTar = tempfile.NamedTemporaryFile(suffix=".tar", delete=False)
|
||||||
with tarfile.open(fileobj=tmpTar, mode='w') as tarball:
|
with tarfile.open(fileobj=tmpTar, mode="w") as tarball:
|
||||||
tarball.add(args.execdir, arcname=os.path.basename(args.execdir))
|
tarball.add(args.execdir, arcname=os.path.basename(args.execdir))
|
||||||
|
|
||||||
# Make sure we close the file before we scp it, because accessing
|
# Make sure we close the file before we scp it, because accessing
|
||||||
@ -93,22 +102,22 @@ def main():
|
|||||||
|
|
||||||
# Untar the dependencies in the temporary directory and remove the tarball.
|
# Untar the dependencies in the temporary directory and remove the tarball.
|
||||||
remoteCommands = [
|
remoteCommands = [
|
||||||
'tar -xf {} -C {} --strip-components 1'.format(remoteTarball, tmp),
|
"tar -xf {} -C {} --strip-components 1".format(remoteTarball, tmp),
|
||||||
'rm {}'.format(remoteTarball)
|
"rm {}".format(remoteTarball),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Make sure all test-executables in the remote command line have 'execute'
|
# Make sure all test-executables in the remote command line have 'execute'
|
||||||
# permissions on the remote host. The host that compiled the test-executable
|
# permissions on the remote host. The host that compiled the test-executable
|
||||||
# might not have a notion of 'executable' permissions.
|
# might not have a notion of 'executable' permissions.
|
||||||
for exe in map(pathOnRemote, filter(isTestExe, commandLine)):
|
for exe in map(pathOnRemote, filter(isTestExe, commandLine)):
|
||||||
remoteCommands.append('chmod +x {}'.format(exe))
|
remoteCommands.append("chmod +x {}".format(exe))
|
||||||
|
|
||||||
# Execute the command through SSH in the temporary directory, with the
|
# Execute the command through SSH in the temporary directory, with the
|
||||||
# correct environment. We tweak the command line to run it on the remote
|
# correct environment. We tweak the command line to run it on the remote
|
||||||
# host by transforming the path of test-executables to their path in the
|
# host by transforming the path of test-executables to their path in the
|
||||||
# temporary directory on the remote host.
|
# temporary directory on the remote host.
|
||||||
commandLine = (pathOnRemote(x) if isTestExe(x) else x for x in commandLine)
|
commandLine = (pathOnRemote(x) if isTestExe(x) else x for x in commandLine)
|
||||||
remoteCommands.append('cd {}'.format(tmp))
|
remoteCommands.append("cd {}".format(tmp))
|
||||||
|
|
||||||
if args.prepend_env:
|
if args.prepend_env:
|
||||||
# We can't sensibly know the original value of the env vars
|
# We can't sensibly know the original value of the env vars
|
||||||
@ -117,17 +126,17 @@ def main():
|
|||||||
|
|
||||||
if args.env:
|
if args.env:
|
||||||
env = list(map(cmd_quote, args.env))
|
env = list(map(cmd_quote, args.env))
|
||||||
remoteCommands.append('export {}'.format(' '.join(args.env)))
|
remoteCommands.append("export {}".format(" ".join(args.env)))
|
||||||
remoteCommands.append(subprocess.list2cmdline(commandLine))
|
remoteCommands.append(subprocess.list2cmdline(commandLine))
|
||||||
|
|
||||||
# Finally, SSH to the remote host and execute all the commands.
|
# Finally, SSH to the remote host and execute all the commands.
|
||||||
rc = subprocess.call(ssh(args, ' && '.join(remoteCommands)))
|
rc = subprocess.call(ssh(args, " && ".join(remoteCommands)))
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# Make sure the temporary directory is removed when we're done.
|
# Make sure the temporary directory is removed when we're done.
|
||||||
subprocess.check_call(ssh(args, 'rm -r {}'.format(tmp)))
|
subprocess.check_call(ssh(args, "rm -r {}".format(tmp)))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
exit(main())
|
exit(main())
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
#
|
#
|
||||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
# See https://llvm.org/LICENSE.txt for license information.
|
# See https://llvm.org/LICENSE.txt for license information.
|
||||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
#
|
#
|
||||||
#===----------------------------------------------------------------------===##
|
# ===----------------------------------------------------------------------===##
|
||||||
"""
|
"""
|
||||||
sym_diff - Compare two symbol lists and output the differences.
|
sym_diff - Compare two symbol lists and output the differences.
|
||||||
"""
|
"""
|
||||||
@ -17,34 +17,60 @@ from libcxx.sym_check import diff, util
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = ArgumentParser(
|
parser = ArgumentParser(
|
||||||
description='Extract a list of symbols from a shared library.')
|
description="Extract a list of symbols from a shared library."
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--names-only', dest='names_only',
|
"--names-only",
|
||||||
help='Only print symbol names',
|
dest="names_only",
|
||||||
action='store_true', default=False)
|
help="Only print symbol names",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--removed-only', dest='removed_only',
|
"--removed-only",
|
||||||
help='Only print removed symbols',
|
dest="removed_only",
|
||||||
action='store_true', default=False)
|
help="Only print removed symbols",
|
||||||
parser.add_argument('--only-stdlib-symbols', dest='only_stdlib',
|
action="store_true",
|
||||||
help="Filter all symbols not related to the stdlib",
|
default=False,
|
||||||
action='store_true', default=False)
|
)
|
||||||
parser.add_argument('--strict', dest='strict',
|
|
||||||
help="Exit with a non-zero status if any symbols "
|
|
||||||
"differ",
|
|
||||||
action='store_true', default=False)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-o', '--output', dest='output',
|
"--only-stdlib-symbols",
|
||||||
help='The output file. stdout is used if not given',
|
dest="only_stdlib",
|
||||||
type=str, action='store', default=None)
|
help="Filter all symbols not related to the stdlib",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--demangle', dest='demangle', action='store_true', default=False)
|
"--strict",
|
||||||
|
dest="strict",
|
||||||
|
help="Exit with a non-zero status if any symbols " "differ",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'old_syms', metavar='old-syms', type=str,
|
"-o",
|
||||||
help='The file containing the old symbol list or a library')
|
"--output",
|
||||||
|
dest="output",
|
||||||
|
help="The output file. stdout is used if not given",
|
||||||
|
type=str,
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'new_syms', metavar='new-syms', type=str,
|
"--demangle", dest="demangle", action="store_true", default=False
|
||||||
help='The file containing the new symbol list or a library')
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"old_syms",
|
||||||
|
metavar="old-syms",
|
||||||
|
type=str,
|
||||||
|
help="The file containing the old symbol list or a library",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"new_syms",
|
||||||
|
metavar="new-syms",
|
||||||
|
type=str,
|
||||||
|
help="The file containing the new symbol list or a library",
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
old_syms_list = util.extract_or_load(args.old_syms)
|
old_syms_list = util.extract_or_load(args.old_syms)
|
||||||
@ -58,15 +84,16 @@ def main():
|
|||||||
if args.removed_only:
|
if args.removed_only:
|
||||||
added = {}
|
added = {}
|
||||||
report, is_break, is_different = diff.report_diff(
|
report, is_break, is_different = diff.report_diff(
|
||||||
added, removed, changed, names_only=args.names_only,
|
added, removed, changed, names_only=args.names_only, demangle=args.demangle
|
||||||
demangle=args.demangle)
|
)
|
||||||
if args.output is None:
|
if args.output is None:
|
||||||
print(report)
|
print(report)
|
||||||
else:
|
else:
|
||||||
with open(args.output, 'w') as f:
|
with open(args.output, "w") as f:
|
||||||
f.write(report + '\n')
|
f.write(report + "\n")
|
||||||
exit_code = 1 if is_break or (args.strict and is_different) else 0
|
exit_code = 1 if is_break or (args.strict and is_different) else 0
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -7,4 +7,5 @@
|
|||||||
lit_config.fatal(
|
lit_config.fatal(
|
||||||
"You seem to be running Lit directly -- you should be running Lit through "
|
"You seem to be running Lit directly -- you should be running Lit through "
|
||||||
"<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
|
"<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
|
||||||
"file is used.")
|
"file is used."
|
||||||
|
)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
def is_arm_linux_eabi(triple):
|
def is_arm_linux_eabi(triple):
|
||||||
return ('arm' in triple) and ('linux' in triple) and ('eabi' in triple)
|
return ("arm" in triple) and ("linux" in triple) and ("eabi" in triple)
|
||||||
|
|
||||||
is_native = hasattr(config.root, 'target_triple') and (config.root.host_triple == config.root.target_triple)
|
|
||||||
|
is_native = hasattr(config.root, "target_triple") and (
|
||||||
|
config.root.host_triple == config.root.target_triple
|
||||||
|
)
|
||||||
if not is_native or not is_arm_linux_eabi(config.root.host_triple):
|
if not is_native or not is_arm_linux_eabi(config.root.host_triple):
|
||||||
config.unsupported = True
|
config.unsupported = True
|
||||||
|
@ -16,106 +16,106 @@ from datetime import date
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#sys.path.insert(0, os.path.abspath('.'))
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
#needs_sphinx = '1.0'
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
|
extensions = ["sphinx.ext.intersphinx", "sphinx.ext.todo"]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = '.rst'
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
#source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'libunwind'
|
project = "libunwind"
|
||||||
copyright = u'2011-%d, LLVM Project' % date.today().year
|
copyright = "2011-%d, LLVM Project" % date.today().year
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '17.0'
|
version = "17.0"
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '17.0'
|
release = "17.0"
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
#language = None
|
# language = None
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
#today = ''
|
# today = ''
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
today_fmt = '%Y-%m-%d'
|
today_fmt = "%Y-%m-%d"
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
exclude_patterns = ['_build']
|
exclude_patterns = ["_build"]
|
||||||
|
|
||||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
#default_role = None
|
# default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
#add_function_parentheses = True
|
# add_function_parentheses = True
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
#add_module_names = True
|
# add_module_names = True
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
show_authors = True
|
show_authors = True
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
pygments_style = 'friendly'
|
pygments_style = "friendly"
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
# A list of ignored prefixes for module index sorting.
|
||||||
#modindex_common_prefix = []
|
# modindex_common_prefix = []
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output ---------------------------------------------------
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'haiku'
|
html_theme = "haiku"
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
#html_theme_options = {}
|
# html_theme_options = {}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
#html_theme_path = []
|
# html_theme_path = []
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
#html_title = None
|
# html_title = None
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
#html_short_title = None
|
# html_short_title = None
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
# of the sidebar.
|
# of the sidebar.
|
||||||
#html_logo = None
|
# html_logo = None
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
# pixels large.
|
# pixels large.
|
||||||
#html_favicon = None
|
# html_favicon = None
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
@ -124,101 +124,95 @@ html_static_path = []
|
|||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
# using the given strftime format.
|
# using the given strftime format.
|
||||||
#html_last_updated_fmt = '%b %d, %Y'
|
# html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
#html_use_smartypants = True
|
# html_use_smartypants = True
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
#html_sidebars = {}
|
# html_sidebars = {}
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
# template names.
|
# template names.
|
||||||
#html_additional_pages = {}
|
# html_additional_pages = {}
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#html_domain_indices = True
|
# html_domain_indices = True
|
||||||
|
|
||||||
# If false, no index is generated.
|
# If false, no index is generated.
|
||||||
#html_use_index = True
|
# html_use_index = True
|
||||||
|
|
||||||
# If true, the index is split into individual pages for each letter.
|
# If true, the index is split into individual pages for each letter.
|
||||||
#html_split_index = False
|
# html_split_index = False
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
# If true, links to the reST sources are added to the pages.
|
||||||
#html_show_sourcelink = True
|
# html_show_sourcelink = True
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
#html_show_sphinx = True
|
# html_show_sphinx = True
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
#html_show_copyright = True
|
# html_show_copyright = True
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
# base URL from which the finished HTML is served.
|
# base URL from which the finished HTML is served.
|
||||||
#html_use_opensearch = ''
|
# html_use_opensearch = ''
|
||||||
|
|
||||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
#html_file_suffix = None
|
# html_file_suffix = None
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'libunwinddoc'
|
htmlhelp_basename = "libunwinddoc"
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output --------------------------------------------------
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
#'papersize': 'letterpaper',
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
#'pointsize': '10pt',
|
||||||
#'pointsize': '10pt',
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#'preamble': '',
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
#'preamble': '',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('contents', 'libunwind.tex', u'libunwind Documentation',
|
("contents", "libunwind.tex", "libunwind Documentation", "LLVM project", "manual"),
|
||||||
u'LLVM project', 'manual'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
# the title page.
|
# the title page.
|
||||||
#latex_logo = None
|
# latex_logo = None
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
# not chapters.
|
# not chapters.
|
||||||
#latex_use_parts = False
|
# latex_use_parts = False
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
# If true, show page references after internal links.
|
||||||
#latex_show_pagerefs = False
|
# latex_show_pagerefs = False
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#latex_show_urls = False
|
# latex_show_urls = False
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
#latex_appendices = []
|
# latex_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#latex_domain_indices = True
|
# latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output --------------------------------------------
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [("contents", "libunwind", "libunwind Documentation", ["LLVM project"], 1)]
|
||||||
('contents', 'libunwind', u'libunwind Documentation',
|
|
||||||
[u'LLVM project'], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#man_show_urls = False
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ------------------------------------------------
|
# -- Options for Texinfo output ------------------------------------------------
|
||||||
@ -227,19 +221,25 @@ man_pages = [
|
|||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('contents', 'libunwind', u'libunwind Documentation',
|
(
|
||||||
u'LLVM project', 'libunwind', 'LLVM Unwinder',
|
"contents",
|
||||||
'Miscellaneous'),
|
"libunwind",
|
||||||
|
"libunwind Documentation",
|
||||||
|
"LLVM project",
|
||||||
|
"libunwind",
|
||||||
|
"LLVM Unwinder",
|
||||||
|
"Miscellaneous",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
#texinfo_appendices = []
|
# texinfo_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#texinfo_domain_indices = True
|
# texinfo_domain_indices = True
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
#texinfo_show_urls = 'footnote'
|
# texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
|
||||||
# FIXME: Define intersphinx configuration.
|
# FIXME: Define intersphinx configuration.
|
||||||
|
@ -7,4 +7,5 @@
|
|||||||
lit_config.fatal(
|
lit_config.fatal(
|
||||||
"You seem to be running Lit directly -- you should be running Lit through "
|
"You seem to be running Lit directly -- you should be running Lit through "
|
||||||
"<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
|
"<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
|
||||||
"file is used.")
|
"file is used."
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user