diff options
Diffstat (limited to 'src/boost/tools/build/test')
351 files changed, 26348 insertions, 0 deletions
diff --git a/src/boost/tools/build/test/BoostBuild.py b/src/boost/tools/build/test/BoostBuild.py new file mode 100644 index 00000000..6e87d8a4 --- /dev/null +++ b/src/boost/tools/build/test/BoostBuild.py @@ -0,0 +1,1348 @@ +# Copyright 2002-2005 Vladimir Prus. +# Copyright 2002-2003 Dave Abrahams. +# Copyright 2006 Rene Rivera. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from __future__ import print_function + +import TestCmd + +import copy +import fnmatch +import glob +import math +import os +import os.path +import re +import shutil +try: + from StringIO import StringIO +except: + from io import StringIO +import subprocess +import sys +import tempfile +import time +import traceback +import tree +import types + +from xml.sax.saxutils import escape + +try: + from functools import reduce +except: + pass + + +def isstr(data): + return isinstance(data, (type(''), type(u''))) + + +class TestEnvironmentError(Exception): + pass + + +annotations = [] + + +def print_annotation(name, value, xml): + """Writes some named bits of information about the current test run.""" + if xml: + print(escape(name) + " {{{") + print(escape(value)) + print("}}}") + else: + print(name + " {{{") + print(value) + print("}}}") + + +def flush_annotations(xml=0): + global annotations + for ann in annotations: + print_annotation(ann[0], ann[1], xml) + annotations = [] + + +def clear_annotations(): + global annotations + annotations = [] + + +defer_annotations = 0 + +def set_defer_annotations(n): + global defer_annotations + defer_annotations = n + + +def annotate_stack_trace(tb=None): + if tb: + trace = TestCmd.caller(traceback.extract_tb(tb), 0) + else: + trace = TestCmd.caller(traceback.extract_stack(), 1) + annotation("stacktrace", trace) + + +def annotation(name, value): + """Records an annotation about the test run.""" + annotations.append((name, value)) + if not defer_annotations: + flush_annotations() + + +def get_toolset(): + toolset = None + for arg in sys.argv[1:]: + if not arg.startswith("-"): + toolset = arg + return toolset or "gcc" + + +# Detect the host OS. +cygwin = hasattr(os, "uname") and os.uname()[0].lower().startswith("cygwin") +windows = cygwin or os.environ.get("OS", "").lower().startswith("windows") + +if cygwin: + default_os = "cygwin" +elif windows: + default_os = "windows" +elif hasattr(os, "uname"): + default_os = os.uname()[0].lower() + +def prepare_prefixes_and_suffixes(toolset, target_os=default_os): + prepare_suffix_map(toolset, target_os) + prepare_library_prefix(toolset, target_os) + + +def prepare_suffix_map(toolset, target_os=default_os): + """ + Set up suffix translation performed by the Boost Build testing framework + to accommodate different toolsets generating targets of the same type using + different filename extensions (suffixes). + + """ + global suffixes + suffixes = {} + if target_os == "cygwin": + suffixes[".lib"] = ".a" + suffixes[".obj"] = ".o" + suffixes[".implib"] = ".lib.a" + elif target_os == "windows": + if toolset == "gcc": + # MinGW + suffixes[".lib"] = ".a" + suffixes[".obj"] = ".o" + suffixes[".implib"] = ".dll.a" + else: + # Everything else Windows + suffixes[".implib"] = ".lib" + else: + suffixes[".exe"] = "" + suffixes[".dll"] = ".so" + suffixes[".lib"] = ".a" + suffixes[".obj"] = ".o" + suffixes[".implib"] = ".no_implib_files_on_this_platform" + + if target_os == "darwin": + suffixes[".dll"] = ".dylib" + + +def prepare_library_prefix(toolset, target_os=default_os): + """ + Setup whether Boost Build is expected to automatically prepend prefixes + to its built library targets. + + """ + global lib_prefix + lib_prefix = "lib" + + global dll_prefix + if target_os == "cygwin": + dll_prefix = "cyg" + elif target_os == "windows" and toolset != "gcc": + dll_prefix = None + else: + dll_prefix = "lib" + + +def re_remove(sequence, regex): + me = re.compile(regex) + result = list(filter(lambda x: me.match(x), sequence)) + if not result: + raise ValueError() + for r in result: + sequence.remove(r) + + +def glob_remove(sequence, pattern): + result = list(fnmatch.filter(sequence, pattern)) + if not result: + raise ValueError() + for r in result: + sequence.remove(r) + + +class Tester(TestCmd.TestCmd): + """Main tester class for Boost Build. + + Optional arguments: + + `arguments` - Arguments passed to the run executable. + `executable` - Name of the executable to invoke. + `match` - Function to use for compating actual and + expected file contents. + `boost_build_path` - Boost build path to be passed to the run + executable. + `translate_suffixes` - Whether to update suffixes on the the file + names passed from the test script so they + match those actually created by the current + toolset. For example, static library files + are specified by using the .lib suffix but + when the "gcc" toolset is used it actually + creates them using the .a suffix. + `pass_toolset` - Whether the test system should pass the + specified toolset to the run executable. + `use_test_config` - Whether the test system should tell the run + executable to read in the test_config.jam + configuration file. + `ignore_toolset_requirements` - Whether the test system should tell the run + executable to ignore toolset requirements. + `workdir` - Absolute directory where the test will be + run from. + `pass_d0` - If set, when tests are not explicitly run + in verbose mode, they are run as silent + (-d0 & --quiet Boost Jam options). + + Optional arguments inherited from the base class: + + `description` - Test description string displayed in case + of a failed test. + `subdir` - List of subdirectories to automatically + create under the working directory. Each + subdirectory needs to be specified + separately, parent coming before its child. + `verbose` - Flag that may be used to enable more + verbose test system output. Note that it + does not also enable more verbose build + system output like the --verbose command + line option does. + """ + def __init__(self, arguments=None, executable="b2", + match=TestCmd.match_exact, boost_build_path=None, + translate_suffixes=True, pass_toolset=True, use_test_config=True, + ignore_toolset_requirements=False, workdir="", pass_d0=False, + **keywords): + + assert arguments.__class__ is not str + self.original_workdir = os.path.dirname(__file__) + if workdir and not os.path.isabs(workdir): + raise ("Parameter workdir <%s> must point to an absolute " + "directory: " % workdir) + + self.last_build_timestamp = 0 + self.translate_suffixes = translate_suffixes + self.use_test_config = use_test_config + + self.toolset = get_toolset() + self.pass_toolset = pass_toolset + self.ignore_toolset_requirements = ignore_toolset_requirements + + prepare_prefixes_and_suffixes(pass_toolset and self.toolset or "gcc") + + use_default_bjam = "--default-bjam" in sys.argv + + if not use_default_bjam: + jam_build_dir = "" + + # Find where jam_src is located. Try for the debug version if it is + # lying around. + srcdir = os.path.join(os.path.dirname(__file__), "..", "src") + dirs = [os.path.join(srcdir, "engine", jam_build_dir + ".debug"), + os.path.join(srcdir, "engine", jam_build_dir)] + for d in dirs: + if os.path.exists(d): + jam_build_dir = d + break + else: + print("Cannot find built Boost.Jam") + sys.exit(1) + + verbosity = ["-d0", "--quiet"] + if not pass_d0: + verbosity = [] + if "--verbose" in sys.argv: + keywords["verbose"] = True + verbosity = ["-d2"] + self.verbosity = verbosity + + if boost_build_path is None: + boost_build_path = self.original_workdir + "/.." + + program_list = [] + if use_default_bjam: + program_list.append(executable) + else: + program_list.append(os.path.join(jam_build_dir, executable)) + program_list.append('-sBOOST_BUILD_PATH="' + boost_build_path + '"') + if arguments: + program_list += arguments + + TestCmd.TestCmd.__init__(self, program=program_list, match=match, + workdir=workdir, inpath=use_default_bjam, **keywords) + + os.chdir(self.workdir) + + def cleanup(self): + try: + TestCmd.TestCmd.cleanup(self) + os.chdir(self.original_workdir) + except AttributeError: + # When this is called during TestCmd.TestCmd.__del__ we can have + # both 'TestCmd' and 'os' unavailable in our scope. Do nothing in + # this case. + pass + + def set_toolset(self, toolset, target_os=default_os): + self.toolset = toolset + self.pass_toolset = True + prepare_prefixes_and_suffixes(toolset, target_os) + + + # + # Methods that change the working directory's content. + # + def set_tree(self, tree_location): + # It is not possible to remove the current directory. + d = os.getcwd() + os.chdir(os.path.dirname(self.workdir)) + shutil.rmtree(self.workdir, ignore_errors=False) + + if not os.path.isabs(tree_location): + tree_location = os.path.join(self.original_workdir, tree_location) + shutil.copytree(tree_location, self.workdir) + + os.chdir(d) + def make_writable(unused, dir, entries): + for e in entries: + name = os.path.join(dir, e) + os.chmod(name, os.stat(name).st_mode | 0o222) + for root, _, files in os.walk("."): + make_writable(None, root, files) + + def write(self, file, content, wait=True): + nfile = self.native_file_name(file) + self.__makedirs(os.path.dirname(nfile), wait) + if not type(content) == bytes: + content = content.encode() + f = open(nfile, "wb") + try: + f.write(content) + finally: + f.close() + self.__ensure_newer_than_last_build(nfile) + + def copy(self, src, dst): + try: + self.write(dst, self.read(src, binary=True)) + except: + self.fail_test(1) + + def copy_preserving_timestamp(self, src, dst): + src_name = self.native_file_name(src) + dst_name = self.native_file_name(dst) + stats = os.stat(src_name) + self.write(dst, self.__read(src, binary=True)) + os.utime(dst_name, (stats.st_atime, stats.st_mtime)) + + def touch(self, names, wait=True): + if isstr(names): + names = [names] + for name in names: + path = self.native_file_name(name) + if wait: + self.__ensure_newer_than_last_build(path) + else: + os.utime(path, None) + + def rm(self, names): + if not type(names) == list: + names = [names] + + if names == ["."]: + # If we are deleting the entire workspace, there is no need to wait + # for a clock tick. + self.last_build_timestamp = 0 + + # Avoid attempts to remove the current directory. + os.chdir(self.original_workdir) + for name in names: + n = glob.glob(self.native_file_name(name)) + if n: n = n[0] + if not n: + n = self.glob_file(name.replace("$toolset", self.toolset + "*") + ) + if n: + if os.path.isdir(n): + shutil.rmtree(n, ignore_errors=False) + else: + os.unlink(n) + + # Create working dir root again in case we removed it. + if not os.path.exists(self.workdir): + os.mkdir(self.workdir) + os.chdir(self.workdir) + + def expand_toolset(self, name): + """ + Expands $toolset placeholder in the given file to the name of the + toolset currently being tested. + + """ + self.write(name, self.read(name).replace("$toolset", self.toolset)) + + def dump_stdio(self): + annotation("STDOUT", self.stdout()) + annotation("STDERR", self.stderr()) + + def run_build_system(self, extra_args=None, subdir="", stdout=None, + stderr="", status=0, match=None, pass_toolset=None, + use_test_config=None, ignore_toolset_requirements=None, + expected_duration=None, **kw): + + assert extra_args.__class__ is not str + + if os.path.isabs(subdir): + print("You must pass a relative directory to subdir <%s>." % subdir + ) + return + + self.previous_tree, dummy = tree.build_tree(self.workdir) + self.wait_for_time_change_since_last_build() + + if match is None: + match = self.match + + if pass_toolset is None: + pass_toolset = self.pass_toolset + + if use_test_config is None: + use_test_config = self.use_test_config + + if ignore_toolset_requirements is None: + ignore_toolset_requirements = self.ignore_toolset_requirements + + try: + kw["program"] = [] + kw["program"] += self.program + if extra_args: + kw["program"] += extra_args + if not extra_args or not any(a.startswith("-j") for a in extra_args): + kw["program"] += ["-j1"] + if stdout is None and not any(a.startswith("-d") for a in kw["program"]): + kw["program"] += self.verbosity + if pass_toolset: + kw["program"].append("toolset=" + self.toolset) + if use_test_config: + kw["program"].append('--test-config="%s"' % os.path.join( + self.original_workdir, "test-config.jam")) + if ignore_toolset_requirements: + kw["program"].append("--ignore-toolset-requirements") + if "--python" in sys.argv: + # -z disables Python optimization mode. + # this enables type checking (all assert + # and if __debug__ statements). + kw["program"].extend(["--python", "-z"]) + if "--stacktrace" in sys.argv: + kw["program"].append("--stacktrace") + kw["chdir"] = subdir + self.last_program_invocation = kw["program"] + build_time_start = time.time() + TestCmd.TestCmd.run(self, **kw) + build_time_finish = time.time() + except: + self.dump_stdio() + raise + + old_last_build_timestamp = self.last_build_timestamp + self.tree, self.last_build_timestamp = tree.build_tree(self.workdir) + self.difference = tree.tree_difference(self.previous_tree, self.tree) + if self.difference.empty(): + # If nothing has been changed by this build and sufficient time has + # passed since the last build that actually changed something, + # there is no need to wait for touched or newly created files to + # start getting newer timestamps than the currently existing ones. + self.last_build_timestamp = old_last_build_timestamp + + self.difference.ignore_directories() + self.unexpected_difference = copy.deepcopy(self.difference) + + if (status and self.status) is not None and self.status != status: + expect = "" + if status != 0: + expect = " (expected %d)" % status + + annotation("failure", '"%s" returned %d%s' % (kw["program"], + self.status, expect)) + + annotation("reason", "unexpected status returned by bjam") + self.fail_test(1) + + if stdout is not None and not match(self.stdout(), stdout): + stdout_test = match(self.stdout(), stdout) + annotation("failure", "Unexpected stdout") + annotation("Expected STDOUT", stdout) + annotation("Actual STDOUT", self.stdout()) + stderr = self.stderr() + if stderr: + annotation("STDERR", stderr) + self.maybe_do_diff(self.stdout(), stdout, stdout_test) + self.fail_test(1, dump_stdio=False) + + # Intel tends to produce some messages to stderr which make tests fail. + intel_workaround = re.compile("^xi(link|lib): executing.*\n", re.M) + actual_stderr = re.sub(intel_workaround, "", self.stderr()) + + if stderr is not None and not match(actual_stderr, stderr): + stderr_test = match(actual_stderr, stderr) + annotation("failure", "Unexpected stderr") + annotation("Expected STDERR", stderr) + annotation("Actual STDERR", self.stderr()) + annotation("STDOUT", self.stdout()) + self.maybe_do_diff(actual_stderr, stderr, stderr_test) + self.fail_test(1, dump_stdio=False) + + if expected_duration is not None: + actual_duration = build_time_finish - build_time_start + if actual_duration > expected_duration: + print("Test run lasted %f seconds while it was expected to " + "finish in under %f seconds." % (actual_duration, + expected_duration)) + self.fail_test(1, dump_stdio=False) + + self.__ignore_junk() + + def glob_file(self, name): + name = self.adjust_name(name) + result = None + if hasattr(self, "difference"): + for f in (self.difference.added_files + + self.difference.modified_files + + self.difference.touched_files): + if fnmatch.fnmatch(f, name): + result = self.__native_file_name(f) + break + if not result: + result = glob.glob(self.__native_file_name(name)) + if result: + result = result[0] + return result + + def __read(self, name, binary=False): + try: + openMode = "r" + if binary: + openMode += "b" + else: + openMode += "U" + f = open(name, openMode) + result = f.read() + f.close() + return result + except: + annotation("failure", "Could not open '%s'" % name) + self.fail_test(1) + return "" + + def read(self, name, binary=False): + name = self.glob_file(name) + return self.__read(name, binary=binary) + + def read_and_strip(self, name): + if not self.glob_file(name): + return "" + f = open(self.glob_file(name), "rb") + lines = f.readlines() + f.close() + result = "\n".join(x.decode().rstrip() for x in lines) + if lines and lines[-1][-1] != "\n": + return result + "\n" + return result + + def fail_test(self, condition, dump_difference=True, dump_stdio=True, + dump_stack=True): + if not condition: + return + + if dump_difference and hasattr(self, "difference"): + f = StringIO() + self.difference.pprint(f) + annotation("changes caused by the last build command", + f.getvalue()) + + if dump_stdio: + self.dump_stdio() + + if "--preserve" in sys.argv: + print() + print("*** Copying the state of working dir into 'failed_test' ***") + print() + path = os.path.join(self.original_workdir, "failed_test") + if os.path.isdir(path): + shutil.rmtree(path, ignore_errors=False) + elif os.path.exists(path): + raise "Path " + path + " already exists and is not a directory" + shutil.copytree(self.workdir, path) + print("The failed command was:") + print(" ".join(self.last_program_invocation)) + + if dump_stack: + annotate_stack_trace() + sys.exit(1) + + # A number of methods below check expectations with actual difference + # between directory trees before and after a build. All the 'expect*' + # methods require exact names to be passed. All the 'ignore*' methods allow + # wildcards. + + # All names can be either a string or a list of strings. + def expect_addition(self, names): + for name in self.adjust_names(names): + try: + glob_remove(self.unexpected_difference.added_files, name) + except: + annotation("failure", "File %s not added as expected" % name) + self.fail_test(1) + + def ignore_addition(self, wildcard): + self.__ignore_elements(self.unexpected_difference.added_files, + wildcard) + + def expect_removal(self, names): + for name in self.adjust_names(names): + try: + glob_remove(self.unexpected_difference.removed_files, name) + except: + annotation("failure", "File %s not removed as expected" % name) + self.fail_test(1) + + def ignore_removal(self, wildcard): + self.__ignore_elements(self.unexpected_difference.removed_files, + wildcard) + + def expect_modification(self, names): + for name in self.adjust_names(names): + try: + glob_remove(self.unexpected_difference.modified_files, name) + except: + annotation("failure", "File %s not modified as expected" % + name) + self.fail_test(1) + + def ignore_modification(self, wildcard): + self.__ignore_elements(self.unexpected_difference.modified_files, + wildcard) + + def expect_touch(self, names): + d = self.unexpected_difference + for name in self.adjust_names(names): + # We need to check both touched and modified files. The reason is + # that: + # (1) Windows binaries such as obj, exe or dll files have slight + # differences even with identical inputs due to Windows PE + # format headers containing an internal timestamp. + # (2) Intel's compiler for Linux has the same behaviour. + filesets = [d.modified_files, d.touched_files] + + while filesets: + try: + glob_remove(filesets[-1], name) + break + except ValueError: + filesets.pop() + + if not filesets: + annotation("failure", "File %s not touched as expected" % name) + self.fail_test(1) + + def ignore_touch(self, wildcard): + self.__ignore_elements(self.unexpected_difference.touched_files, + wildcard) + + def ignore(self, wildcard): + self.ignore_addition(wildcard) + self.ignore_removal(wildcard) + self.ignore_modification(wildcard) + self.ignore_touch(wildcard) + + def expect_nothing(self, names): + for name in self.adjust_names(names): + if name in self.difference.added_files: + annotation("failure", + "File %s added, but no action was expected" % name) + self.fail_test(1) + if name in self.difference.removed_files: + annotation("failure", + "File %s removed, but no action was expected" % name) + self.fail_test(1) + pass + if name in self.difference.modified_files: + annotation("failure", + "File %s modified, but no action was expected" % name) + self.fail_test(1) + if name in self.difference.touched_files: + annotation("failure", + "File %s touched, but no action was expected" % name) + self.fail_test(1) + + def __ignore_junk(self): + # Not totally sure about this change, but I do not see a good + # alternative. + if windows: + self.ignore("*.ilk") # MSVC incremental linking files. + self.ignore("*.pdb") # MSVC program database files. + self.ignore("*.rsp") # Response files. + self.ignore("*.tds") # Borland debug symbols. + self.ignore("*.manifest") # MSVC DLL manifests. + self.ignore("bin/standalone/msvc/*/msvc-setup.bat") + + # Debug builds of bjam built with gcc produce this profiling data. + self.ignore("gmon.out") + self.ignore("*/gmon.out") + + # Boost Build's 'configure' functionality (unfinished at the time) + # produces this file. + self.ignore("bin/config.log") + self.ignore("bin/project-cache.jam") + + # Compiled Python files created when running Python based Boost Build. + self.ignore("*.pyc") + + # OSX/Darwin files and dirs. + self.ignore("*.dSYM/*") + + def expect_nothing_more(self): + if not self.unexpected_difference.empty(): + annotation("failure", "Unexpected changes found") + output = StringIO() + self.unexpected_difference.pprint(output) + annotation("unexpected changes", output.getvalue()) + self.fail_test(1) + + def expect_output_lines(self, lines, expected=True): + self.__expect_lines(self.stdout(), lines, expected) + + def expect_content_lines(self, filename, line, expected=True): + self.__expect_lines(self.read_and_strip(filename), line, expected) + + def expect_content(self, name, content, exact=False): + actual = self.read(name) + content = content.replace("$toolset", self.toolset + "*") + + matched = False + if exact: + matched = fnmatch.fnmatch(actual, content) + else: + def sorted_(z): + z.sort(key=lambda x: x.lower().replace("\\", "/")) + return z + actual_ = list(map(lambda x: sorted_(x.split()), actual.splitlines())) + content_ = list(map(lambda x: sorted_(x.split()), content.splitlines())) + if len(actual_) == len(content_): + matched = map( + lambda x, y: map(lambda n, p: fnmatch.fnmatch(n, p), x, y), + actual_, content_) + matched = reduce( + lambda x, y: x and reduce( + lambda a, b: a and b, + y, True), + matched, True) + + if not matched: + print("Expected:\n") + print(content) + print("Got:\n") + print(actual) + self.fail_test(1) + + def maybe_do_diff(self, actual, expected, result=None): + if os.environ.get("DO_DIFF"): + e = tempfile.mktemp("expected") + a = tempfile.mktemp("actual") + f = open(e, "w") + f.write(expected) + f.close() + f = open(a, "w") + f.write(actual) + f.close() + print("DIFFERENCE") + # Current diff should return 1 to indicate 'different input files' + # but some older diff versions may return 0 and depending on the + # exact Python/OS platform version, os.system() call may gobble up + # the external process's return code and return 0 itself. + if os.system('diff -u "%s" "%s"' % (e, a)) not in [0, 1]: + print('Unable to compute difference: diff -u "%s" "%s"' % (e, a + )) + os.unlink(e) + os.unlink(a) + elif type(result) is TestCmd.MatchError: + print(result.message) + else: + print("Set environmental variable 'DO_DIFF' to examine the " + "difference.") + + # Internal methods. + def adjust_lib_name(self, name): + global lib_prefix + global dll_prefix + result = name + + pos = name.rfind(".") + if pos != -1: + suffix = name[pos:] + if suffix == ".lib": + (head, tail) = os.path.split(name) + if lib_prefix: + tail = lib_prefix + tail + result = os.path.join(head, tail) + elif suffix == ".dll" or suffix == ".implib": + (head, tail) = os.path.split(name) + if dll_prefix: + tail = dll_prefix + tail + result = os.path.join(head, tail) + # If we want to use this name in a Jamfile, we better convert \ to /, + # as otherwise we would have to quote \. + result = result.replace("\\", "/") + return result + + def adjust_suffix(self, name): + if not self.translate_suffixes: + return name + pos = name.rfind(".") + if pos == -1: + return name + suffix = name[pos:] + return name[:pos] + suffixes.get(suffix, suffix) + + # Acceps either a string or a list of strings and returns a list of + # strings. Adjusts suffixes on all names. + def adjust_names(self, names): + if isstr(names): + names = [names] + r = map(self.adjust_lib_name, names) + r = map(self.adjust_suffix, r) + r = map(lambda x, t=self.toolset: x.replace("$toolset", t + "*"), r) + return list(r) + + def adjust_name(self, name): + return self.adjust_names(name)[0] + + def __native_file_name(self, name): + return os.path.normpath(os.path.join(self.workdir, *name.split("/"))) + + def native_file_name(self, name): + return self.__native_file_name(self.adjust_name(name)) + + def wait_for_time_change(self, path, touch): + """ + Wait for newly assigned file system modification timestamps for the + given path to become large enough for the timestamp difference to be + correctly recognized by both this Python based testing framework and + the Boost Jam executable being tested. May optionally touch the given + path to set its modification timestamp to the new value. + + """ + self.__wait_for_time_change(path, touch, last_build_time=False) + + def wait_for_time_change_since_last_build(self): + """ + Wait for newly assigned file system modification timestamps to + become large enough for the timestamp difference to be + correctly recognized by the Python based testing framework. + Does not care about Jam's timestamp resolution, since we + only need this to detect touched files. + """ + if self.last_build_timestamp: + timestamp_file = "timestamp-3df2f2317e15e4a9" + open(timestamp_file, "wb").close() + self.__wait_for_time_change_impl(timestamp_file, + self.last_build_timestamp, + self.__python_timestamp_resolution(timestamp_file, 0), 0) + os.unlink(timestamp_file) + + def __build_timestamp_resolution(self): + """ + Returns the minimum path modification timestamp resolution supported + by the used Boost Jam executable. + + """ + dir = tempfile.mkdtemp("bjam_version_info") + try: + jam_script = "timestamp_resolution.jam" + f = open(os.path.join(dir, jam_script), "w") + try: + f.write("EXIT $(JAM_TIMESTAMP_RESOLUTION) : 0 ;") + finally: + f.close() + p = subprocess.Popen([self.program[0], "-d0", "-f%s" % jam_script], + stdout=subprocess.PIPE, cwd=dir, universal_newlines=True) + out, err = p.communicate() + finally: + shutil.rmtree(dir, ignore_errors=False) + + if p.returncode != 0: + raise TestEnvironmentError("Unexpected return code (%s) when " + "detecting Boost Jam's minimum supported path modification " + "timestamp resolution version information." % p.returncode) + if err: + raise TestEnvironmentError("Unexpected error output (%s) when " + "detecting Boost Jam's minimum supported path modification " + "timestamp resolution version information." % err) + + r = re.match("([0-9]{2}):([0-9]{2}):([0-9]{2}\\.[0-9]{9})$", out) + if not r: + # Older Boost Jam versions did not report their minimum supported + # path modification timestamp resolution and did not actually + # support path modification timestamp resolutions finer than 1 + # second. + # TODO: Phase this support out to avoid such fallback code from + # possibly covering up other problems. + return 1 + if r.group(1) != "00" or r.group(2) != "00": # hours, minutes + raise TestEnvironmentError("Boost Jam with too coarse minimum " + "supported path modification timestamp resolution (%s:%s:%s)." + % (r.group(1), r.group(2), r.group(3))) + return float(r.group(3)) # seconds.nanoseconds + + def __ensure_newer_than_last_build(self, path): + """ + Updates the given path's modification timestamp after waiting for the + newly assigned file system modification timestamp to become large + enough for the timestamp difference between it and the last build + timestamp to be correctly recognized by both this Python based testing + framework and the Boost Jam executable being tested. Does nothing if + there is no 'last build' information available. + + """ + if self.last_build_timestamp: + self.__wait_for_time_change(path, touch=True, last_build_time=True) + + def __expect_lines(self, data, lines, expected): + """ + Checks whether the given data contains the given lines. + + Data may be specified as a single string containing text lines + separated by newline characters. + + Lines may be specified in any of the following forms: + * Single string containing text lines separated by newlines - the + given lines are searched for in the given data without any extra + data lines between them. + * Container of strings containing text lines separated by newlines + - the given lines are searched for in the given data with extra + data lines allowed between lines belonging to different strings. + * Container of strings containing text lines separated by newlines + and containers containing strings - the same as above with the + internal containers containing strings being interpreted as if + all their content was joined together into a single string + separated by newlines. + + A newline at the end of any multi-line lines string is interpreted as + an expected extra trailig empty line. + """ + # str.splitlines() trims at most one trailing newline while we want the + # trailing newline to indicate that there should be an extra empty line + # at the end. + def splitlines(x): + return (x + "\n").splitlines() + + if data is None: + data = [] + elif isstr(data): + data = splitlines(data) + + if isstr(lines): + lines = [splitlines(lines)] + else: + expanded = [] + for x in lines: + if isstr(x): + x = splitlines(x) + expanded.append(x) + lines = expanded + + if _contains_lines(data, lines) != bool(expected): + output = [] + if expected: + output = ["Did not find expected lines:"] + else: + output = ["Found unexpected lines:"] + first = True + for line_sequence in lines: + if line_sequence: + if first: + first = False + else: + output.append("...") + output.extend(" > " + line for line in line_sequence) + output.append("in output:") + output.extend(" > " + line for line in data) + annotation("failure", "\n".join(output)) + self.fail_test(1) + + def __ignore_elements(self, things, wildcard): + """Removes in-place 'things' elements matching the given 'wildcard'.""" + things[:] = list(filter(lambda x: not fnmatch.fnmatch(x, wildcard), things)) + + def __makedirs(self, path, wait): + """ + Creates a folder with the given path, together with any missing + parent folders. If WAIT is set, makes sure any newly created folders + have modification timestamps newer than the ones left behind by the + last build run. + + """ + try: + if wait: + stack = [] + while path and path not in stack and not os.path.isdir(path): + stack.append(path) + path = os.path.dirname(path) + while stack: + path = stack.pop() + os.mkdir(path) + self.__ensure_newer_than_last_build(path) + else: + os.makedirs(path) + except Exception: + pass + + def __python_timestamp_resolution(self, path, minimum_resolution): + """ + Returns the modification timestamp resolution for the given path + supported by the used Python interpreter/OS/filesystem combination. + Will not check for resolutions less than the given minimum value. Will + change the path's modification timestamp in the process. + + Return values: + 0 - nanosecond resolution supported + positive decimal - timestamp resolution in seconds + + """ + # Note on Python's floating point timestamp support: + # Python interpreter versions prior to Python 2.3 did not support + # floating point timestamps. Versions 2.3 through 3.3 may or may not + # support it depending on the configuration (may be toggled by calling + # os.stat_float_times(True/False) at program startup, disabled by + # default prior to Python 2.5 and enabled by default since). Python 3.3 + # deprecated this configuration and 3.4 removed support for it after + # which floating point timestamps are always supported. + ver = sys.version_info[0:2] + python_nanosecond_support = ver >= (3, 4) or (ver >= (2, 3) and + os.stat_float_times()) + + # Minimal expected floating point difference used to account for + # possible imprecise floating point number representations. We want + # this number to be small (at least smaller than 0.0001) but still + # large enough that we can be sure that increasing a floating point + # value by 2 * eta guarantees the value read back will be increased by + # at least eta. + eta = 0.00005 + + stats_orig = os.stat(path) + def test_time(diff): + """Returns whether a timestamp difference is detectable.""" + os.utime(path, (stats_orig.st_atime, stats_orig.st_mtime + diff)) + return os.stat(path).st_mtime > stats_orig.st_mtime + eta + + # Test for nanosecond timestamp resolution support. + if not minimum_resolution and python_nanosecond_support: + if test_time(2 * eta): + return 0 + + # Detect the filesystem timestamp resolution. Note that there is no + # need to make this code 'as fast as possible' as, this function gets + # called before having to sleep until the next detectable modification + # timestamp value and that, since we already know nanosecond resolution + # is not supported, will surely take longer than whatever we do here to + # detect this minimal detectable modification timestamp resolution. + step = 0.1 + if not python_nanosecond_support: + # If Python does not support nanosecond timestamp resolution we + # know the minimum possible supported timestamp resolution is 1 + # second. + minimum_resolution = max(1, minimum_resolution) + index = max(1, int(minimum_resolution / step)) + while step * index < minimum_resolution: + # Floating point number representation errors may cause our + # initially calculated start index to be too small if calculated + # directly. + index += 1 + while True: + # Do not simply add up the steps to avoid cumulative floating point + # number representation errors. + next = step * index + if next > 10: + raise TestEnvironmentError("File systems with too coarse " + "modification timestamp resolutions not supported.") + if test_time(next): + return next + index += 1 + + def __wait_for_time_change(self, path, touch, last_build_time): + """ + Wait until a newly assigned file system modification timestamp for + the given path is large enough for the timestamp difference between it + and the last build timestamp or the path's original file system + modification timestamp (depending on the last_build_time flag) to be + correctly recognized by both this Python based testing framework and + the Boost Jam executable being tested. May optionally touch the given + path to set its modification timestamp to the new value. + + """ + assert self.last_build_timestamp or not last_build_time + stats_orig = os.stat(path) + + if last_build_time: + start_time = self.last_build_timestamp + else: + start_time = stats_orig.st_mtime + + build_resolution = self.__build_timestamp_resolution() + assert build_resolution >= 0 + + # Check whether the current timestamp is already new enough. + if stats_orig.st_mtime > start_time and (not build_resolution or + stats_orig.st_mtime >= start_time + build_resolution): + return + + resolution = self.__python_timestamp_resolution(path, build_resolution) + assert resolution >= build_resolution + self.__wait_for_time_change_impl(path, start_time, resolution, build_resolution) + + if not touch: + os.utime(path, (stats_orig.st_atime, stats_orig.st_mtime)) + + def __wait_for_time_change_impl(self, path, start_time, resolution, build_resolution): + # Implementation notes: + # * Theoretically time.sleep() API might get interrupted too soon + # (never actually encountered). + # * We encountered cases where we sleep just long enough for the + # filesystem's modifiction timestamp to change to the desired value, + # but after waking up, the read timestamp is still just a tiny bit + # too small (encountered on Windows). This is most likely caused by + # imprecise floating point timestamp & sleep interval representation + # used by Python. Note though that we never encountered a case where + # more than one additional tiny sleep() call was needed to remedy + # the situation. + # * We try to wait long enough for the timestamp to change, but do not + # want to waste processing time by waiting too long. The main + # problem is that when we have a coarse resolution, the actual times + # get rounded and we do not know the exact sleep time needed for the + # difference between two such times to pass. E.g. if we have a 1 + # second resolution and the original and the current file timestamps + # are both 10 seconds then it could be that the current time is + # 10.99 seconds and that we can wait for just one hundredth of a + # second for the current file timestamp to reach its next value, and + # using a longer sleep interval than that would just be wasting + # time. + while True: + os.utime(path, None) + c = os.stat(path).st_mtime + if resolution: + if c > start_time and (not build_resolution or c >= start_time + + build_resolution): + break + if c <= start_time - resolution: + # Move close to the desired timestamp in one sleep, but not + # close enough for timestamp rounding to potentially cause + # us to wait too long. + if start_time - c > 5: + if last_build_time: + error_message = ("Last build time recorded as " + "being a future event, causing a too long " + "wait period. Something must have played " + "around with the system clock.") + else: + error_message = ("Original path modification " + "timestamp set to far into the future or " + "something must have played around with the " + "system clock, causing a too long wait " + "period.\nPath: '%s'" % path) + raise TestEnvironmentError(message) + _sleep(start_time - c) + else: + # We are close to the desired timestamp so take baby sleeps + # to avoid sleeping too long. + _sleep(max(0.01, resolution / 10)) + else: + if c > start_time: + break + _sleep(max(0.01, start_time - c)) + + +class List: + def __init__(self, s=""): + elements = [] + if isstr(s): + # Have to handle escaped spaces correctly. + elements = s.replace("\ ", "\001").split() + else: + elements = s + self.l = [e.replace("\001", " ") for e in elements] + + def __len__(self): + return len(self.l) + + def __getitem__(self, key): + return self.l[key] + + def __setitem__(self, key, value): + self.l[key] = value + + def __delitem__(self, key): + del self.l[key] + + def __str__(self): + return str(self.l) + + def __repr__(self): + return "%s.List(%r)" % (self.__module__, " ".join(self.l)) + + def __mul__(self, other): + result = List() + if not isinstance(other, List): + other = List(other) + for f in self: + for s in other: + result.l.append(f + s) + return result + + def __rmul__(self, other): + if not isinstance(other, List): + other = List(other) + return List.__mul__(other, self) + + def __add__(self, other): + result = List() + result.l = self.l[:] + other.l[:] + return result + + +def _contains_lines(data, lines): + data_line_count = len(data) + expected_line_count = reduce(lambda x, y: x + len(y), lines, 0) + index = 0 + for expected in lines: + if expected_line_count > data_line_count - index: + return False + expected_line_count -= len(expected) + index = _match_line_sequence(data, index, data_line_count - + expected_line_count, expected) + if index < 0: + return False + return True + + +def _match_line_sequence(data, start, end, lines): + if not lines: + return start + for index in range(start, end - len(lines) + 1): + data_index = index + for expected in lines: + if not fnmatch.fnmatch(data[data_index], expected): + break + data_index += 1 + else: + return data_index + return -1 + + +def _sleep(delay): + if delay > 5: + raise TestEnvironmentError("Test environment error: sleep period of " + "more than 5 seconds requested. Most likely caused by a file with " + "its modification timestamp set to sometime in the future.") + time.sleep(delay) + + +############################################################################### +# +# Initialization. +# +############################################################################### + +# Make os.stat() return file modification times as floats instead of integers +# to get the best possible file timestamp resolution available. The exact +# resolution depends on the underlying file system and the Python os.stat() +# implementation. The better the resolution we achieve, the shorter we need to +# wait for files we create to start getting new timestamps. +# +# Additional notes: +# * os.stat_float_times() function first introduced in Python 2.3. and +# suggested for deprecation in Python 3.3. +# * On Python versions 2.5+ we do not need to do this as there os.stat() +# returns floating point file modification times by default. +# * Windows CPython implementations prior to version 2.5 do not support file +# modification timestamp resolutions of less than 1 second no matter whether +# these timestamps are returned as integer or floating point values. +# * Python documentation states that this should be set in a program's +# __main__ module to avoid affecting other libraries that might not be ready +# to support floating point timestamps. Since we use no such external +# libraries, we ignore this warning to make it easier to enable this feature +# in both our single & multiple-test scripts. +if (2, 3) <= sys.version_info < (2, 5) and not os.stat_float_times(): + os.stat_float_times(True) + + +# Quickie tests. Should use doctest instead. +if __name__ == "__main__": + assert str(List("foo bar") * "/baz") == "['foo/baz', 'bar/baz']" + assert repr("foo/" * List("bar baz")) == "__main__.List('foo/bar foo/baz')" + + assert _contains_lines([], []) + assert _contains_lines([], [[]]) + assert _contains_lines([], [[], []]) + assert _contains_lines([], [[], [], []]) + assert not _contains_lines([], [[""]]) + assert not _contains_lines([], [["a"]]) + + assert _contains_lines([""], []) + assert _contains_lines(["a"], []) + assert _contains_lines(["a", "b"], []) + assert _contains_lines(["a", "b"], [[], [], []]) + + assert _contains_lines([""], [[""]]) + assert not _contains_lines([""], [["a"]]) + assert not _contains_lines(["a"], [[""]]) + assert _contains_lines(["a", "", "b", ""], [["a"]]) + assert _contains_lines(["a", "", "b", ""], [[""]]) + assert _contains_lines(["a", "", "b"], [["b"]]) + assert not _contains_lines(["a", "b"], [[""]]) + assert not _contains_lines(["a", "", "b", ""], [["c"]]) + assert _contains_lines(["a", "", "b", "x"], [["x"]]) + + data = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] + assert _contains_lines(data, [["1", "2"]]) + assert not _contains_lines(data, [["2", "1"]]) + assert not _contains_lines(data, [["1", "3"]]) + assert not _contains_lines(data, [["1", "3"]]) + assert _contains_lines(data, [["1"], ["2"]]) + assert _contains_lines(data, [["1"], [], [], [], ["2"]]) + assert _contains_lines(data, [["1"], ["3"]]) + assert not _contains_lines(data, [["3"], ["1"]]) + assert _contains_lines(data, [["3"], ["7"], ["8"]]) + assert not _contains_lines(data, [["1"], ["3", "5"]]) + assert not _contains_lines(data, [["1"], [""], ["5"]]) + assert not _contains_lines(data, [["1"], ["5"], ["3"]]) + assert not _contains_lines(data, [["1"], ["5", "3"]]) + + assert not _contains_lines(data, [[" 3"]]) + assert not _contains_lines(data, [["3 "]]) + assert not _contains_lines(data, [["3", ""]]) + assert not _contains_lines(data, [["", "3"]]) + + print("tests passed") diff --git a/src/boost/tools/build/test/Jamfile.jam b/src/boost/tools/build/test/Jamfile.jam new file mode 100644 index 00000000..7ec0bf30 --- /dev/null +++ b/src/boost/tools/build/test/Jamfile.jam @@ -0,0 +1,29 @@ +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import python ; +import testing ; + +if ! [ python.configured ] +{ + using python ; +} + +# Not quite perfect, but good enough for most purposes +local test-files = [ glob *.py ] ; + +local boost-build-files = [ glob + ../src/tools/*.jam + ../src/tools/*/*.jam + ../src/build/*.jam + ../src/util/*.jam + ../src/kernel/*.jam + ../src/options/*.jam + ../src/*.jam ] ; + +testing.make-test run-pyd : test_all.py : + <dependency>$(test-files) + <dependency>$(boost-build-files) + ; diff --git a/src/boost/tools/build/test/MockToolset.py b/src/boost/tools/build/test/MockToolset.py new file mode 100755 index 00000000..a692a686 --- /dev/null +++ b/src/boost/tools/build/test/MockToolset.py @@ -0,0 +1,267 @@ +#!/usr/bin/python + +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import sys + +def create(t): + t.write('''mockinfo.py''', ''' +from __future__ import print_function +import re +import optparse +import os + +parser = optparse.OptionParser() +parser.add_option('-o', dest="output_file") +parser.add_option('-x', dest="language") +parser.add_option('-c', dest="compile", action="store_true") +parser.add_option('-I', dest="includes", action="append") +parser.add_option('-D', dest="defines", action="append") +parser.add_option('-L', dest="library_path", action="append") +parser.add_option('--dll', dest="dll", action="store_true") +parser.add_option('--archive', dest="archive", action="store_true") +parser.add_option('--static-lib', dest="static_libraries", action="append") +parser.add_option('--shared-lib', dest="shared_libraries", action="append") + +cwd = os.environ["JAM_CWD"] + +class MockInfo(object): + def __init__(self, verbose=False): + self.files = dict() + self.commands = list() + self.verbose = verbose + def source_file(self, name, pattern): + self.files[name] = pattern + def action(self, command, status=0): + if isinstance(command, str): + command = command.split() + self.commands.append((command, status)) + def check(self, command): + print("Testing command", command) + for (raw, status) in self.commands: + if self.matches(raw, command): + return status + def matches(self, raw, command): + (expected_options, expected_args) = parser.parse_args(raw) + options = command[0] + input_files = list(command[1]) + if self.verbose: + print(" - matching against", (expected_options, expected_args)) + if len(expected_args) != len(input_files): + if self.verbose: + print(" argument list sizes differ") + return False + for arg in expected_args: + if arg.startswith('$'): + fileid = arg[1:] + pattern = self.files[fileid] if fileid in self.files else fileid + matching_file = None + for input_file in input_files: + with open(input_file, 'r') as f: + contents = f.read() + if pattern == contents: + matching_file = input_file + break + if matching_file is not None: + input_files.remove(matching_file) + else: + if self.verbose: + print(" Failed to match input file contents: %s" % arg) + return False + else: + if arg in input_files: + input_files.remove(arg) + else: + if self.verbose: + print(" Failed to match input file: %s" % arg) + return False + + if options.language != expected_options.language: + if self.verbose: + print(" Failed to match -c") + return False + + if options.compile != expected_options.compile: + if self.verbose: + print(" Failed to match -x") + return False + + # Normalize a path for comparison purposes + def adjust_path(p): + return os.path.normcase(os.path.normpath(os.path.join(cwd, p))) + + # order matters + if options.includes is None: + options.includes = [] + if expected_options.includes is None: + expected_options.includes = [] + if list(map(adjust_path, options.includes)) != \ + list(map(adjust_path, expected_options.includes)): + if self.verbose: + print(" Failed to match -I ", list(map(adjust_path, options.includes)), \ + " != ", list(map(adjust_path, expected_options.includes))) + return False + + if options.defines is None: + options.defines = [] + if expected_options.defines is None: + expected_options.defines = [] + if options.defines != expected_options.defines: + if self.verbose: + print(" Failed to match -I ", options.defines, \ + " != ", expected_options.defines) + return False + + if options.library_path is None: + options.library_path = [] + if expected_options.library_path is None: + expected_options.library_path = [] + if list(map(adjust_path, options.library_path)) != \ + list(map(adjust_path, expected_options.library_path)): + if self.verbose: + print(" Failed to match -L ", list(map(adjust_path, options.library_path)), \ + " != ", list(map(adjust_path, expected_options.library_path))) + return False + + if options.static_libraries != expected_options.static_libraries: + if self.verbose: + print(" Failed to match --static-lib") + return False + + if options.shared_libraries != expected_options.shared_libraries: + if self.verbose: + print(" Failed to match --shared-lib") + return False + + if options.dll != expected_options.dll: + if self.verbose: + print(" Failed to match --dll") + return False + + if options.archive != expected_options.archive: + if self.verbose: + print(" Failed to match --archive") + return False + + # The output must be handled after everything else + # is validated + if expected_options.output_file is not None: + if options.output_file is not None: + if expected_options.output_file.startswith('$'): + fileid = expected_options.output_file[1:] + if fileid not in self.files: + self.files[fileid] = fileid + else: + assert(self.files[fileid] == fileid) + with open(options.output_file, 'w') as output: + output.write(fileid) + else: + if self.verbose: + print("Failed to match -o") + return False + elif options.output_file is not None: + if self.verbose: + print("Failed to match -o") + return False + + # if we've gotten here, then everything matched + if self.verbose: + print(" Matched") + return True +''') + + t.write('mock.py', ''' +from __future__ import print_function +import mockinfo +import markup +import sys + +status = markup.info.check(mockinfo.parser.parse_args()) +if status is not None: + exit(status) +else: + print("Unrecognized command: " + ' '.join(sys.argv)) + exit(1) +''') + + t.write('mock.jam', ''' +import feature ; +import toolset ; +import path ; +import modules ; +import common ; +import type ; + +.python-cmd = "\"%s\"" ; + +# Behave the same as gcc on Windows, because that's what +# the test system expects +type.set-generated-target-prefix SHARED_LIB : <toolset>mock <target-os>windows : lib ; +type.set-generated-target-suffix STATIC_LIB : <toolset>mock <target-os>windows : a ; + +rule init ( ) +{ + local here = [ path.make [ modules.binding $(__name__) ] ] ; + here = [ path.native [ path.root [ path.parent $(here) ] [ path.pwd ] ] ] ; + .config-cmd = [ common.variable-setting-command JAM_CWD : $(here) ] $(.python-cmd) -B ; +} + +feature.extend toolset : mock ; + +generators.register-c-compiler mock.compile.c++ : CPP : OBJ : <toolset>mock ; +generators.register-c-compiler mock.compile.c : C : OBJ : <toolset>mock ; + +generators.register-linker mock.link : LIB OBJ : EXE : <toolset>mock ; +generators.register-linker mock.link.dll : LIB OBJ : SHARED_LIB : <toolset>mock ; +generators.register-archiver mock.archive : OBJ : STATIC_LIB : <toolset>mock ; + +toolset.flags mock.compile OPTIONS <link>shared : -fPIC ; +toolset.flags mock.compile INCLUDES : <include> ; +toolset.flags mock.compile DEFINES : <define> ; + +actions compile.c +{ + $(.config-cmd) mock.py -c -x c -I"$(INCLUDES)" -D"$(DEFINES)" "$(>)" -o "$(<)" +} + +actions compile.c++ +{ + $(.config-cmd) mock.py -c -x c++ -I"$(INCLUDES)" -D"$(DEFINES)" "$(>)" -o "$(<)" +} + +toolset.flags mock.link USER_OPTIONS <linkflags> ; +toolset.flags mock.link FINDLIBS-STATIC <find-static-library> ; +toolset.flags mock.link FINDLIBS-SHARED <find-shared-library> ; +toolset.flags mock.link LINK_PATH <library-path> ; +toolset.flags mock.link LIBRARIES <library-file> ; + +actions link +{ + $(.config-cmd) mock.py "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED) +} + +actions archive +{ + $(.config-cmd) mock.py --archive "$(>)" -o "$(<)" $(USER_OPTIONS) +} + +actions link.dll +{ + $(.config-cmd) mock.py --dll "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED) +} + +''' % sys.executable.replace('\\', '\\\\')) + +def set_expected(t, markup): + verbose = "True" if t.verbose else "False" + t.write('markup.py', ''' +import mockinfo +info = mockinfo.MockInfo(%s) +def source_file(name, contents): + info.source_file(name, contents) +def action(command, status=0): + info.action(command, status) +''' % (verbose) + markup) diff --git a/src/boost/tools/build/test/TestCmd.py b/src/boost/tools/build/test/TestCmd.py new file mode 100644 index 00000000..3f9c2a3c --- /dev/null +++ b/src/boost/tools/build/test/TestCmd.py @@ -0,0 +1,609 @@ +""" +TestCmd.py: a testing framework for commands and scripts. + +The TestCmd module provides a framework for portable automated testing of +executable commands and scripts (in any language, not just Python), especially +commands and scripts that require file system interaction. + +In addition to running tests and evaluating conditions, the TestCmd module +manages and cleans up one or more temporary workspace directories, and provides +methods for creating files and directories in those workspace directories from +in-line data, here-documents), allowing tests to be completely self-contained. + +A TestCmd environment object is created via the usual invocation: + + test = TestCmd() + +The TestCmd module provides pass_test(), fail_test(), and no_result() unbound +methods that report test results for use with the Aegis change management +system. These methods terminate the test immediately, reporting PASSED, FAILED +or NO RESULT respectively and exiting with status 0 (success), 1 or 2 +respectively. This allows for a distinction between an actual failed test and a +test that could not be properly evaluated because of an external condition (such +as a full file system or incorrect permissions). + +""" + +# Copyright 2000 Steven Knight +# This module is free software, and you may redistribute it and/or modify +# it under the same terms as Python itself, so long as this copyright message +# and disclaimer are retained in their original form. +# +# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF +# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. +# +# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, +# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +# Copyright 2002-2003 Vladimir Prus. +# Copyright 2002-2003 Dave Abrahams. +# Copyright 2006 Rene Rivera. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from __future__ import print_function + +__author__ = "Steven Knight <knight@baldmt.com>" +__revision__ = "TestCmd.py 0.D002 2001/08/31 14:56:12 software" +__version__ = "0.02" + +from types import * + +import os +import os.path +import re +import shutil +import stat +import subprocess +import sys +import tempfile +import traceback + + +tempfile.template = 'testcmd.' + +_Cleanup = [] + +def _clean(): + global _Cleanup + list = _Cleanup[:] + _Cleanup = [] + list.reverse() + for test in list: + test.cleanup() + +sys.exitfunc = _clean + + +def caller(tblist, skip): + string = "" + arr = [] + for file, line, name, text in tblist: + if file[-10:] == "TestCmd.py": + break + arr = [(file, line, name, text)] + arr + atfrom = "at" + for file, line, name, text in arr[skip:]: + if name == "?": + name = "" + else: + name = " (" + name + ")" + string = string + ("%s line %d of %s%s\n" % (atfrom, line, file, name)) + atfrom = "\tfrom" + return string + + +def fail_test(self=None, condition=True, function=None, skip=0): + """Cause the test to fail. + + By default, the fail_test() method reports that the test FAILED and exits + with a status of 1. If a condition argument is supplied, the test fails + only if the condition is true. + + """ + if not condition: + return + if not function is None: + function() + of = "" + desc = "" + sep = " " + if not self is None: + if self.program: + of = " of " + " ".join(self.program) + sep = "\n\t" + if self.description: + desc = " [" + self.description + "]" + sep = "\n\t" + + at = caller(traceback.extract_stack(), skip) + + sys.stderr.write("FAILED test" + of + desc + sep + at + """ +in directory: """ + os.getcwd() ) + sys.exit(1) + + +def no_result(self=None, condition=True, function=None, skip=0): + """Causes a test to exit with no valid result. + + By default, the no_result() method reports NO RESULT for the test and + exits with a status of 2. If a condition argument is supplied, the test + fails only if the condition is true. + + """ + if not condition: + return + if not function is None: + function() + of = "" + desc = "" + sep = " " + if not self is None: + if self.program: + of = " of " + self.program + sep = "\n\t" + if self.description: + desc = " [" + self.description + "]" + sep = "\n\t" + + at = caller(traceback.extract_stack(), skip) + sys.stderr.write("NO RESULT for test" + of + desc + sep + at) + sys.exit(2) + + +def pass_test(self=None, condition=True, function=None): + """Causes a test to pass. + + By default, the pass_test() method reports PASSED for the test and exits + with a status of 0. If a condition argument is supplied, the test passes + only if the condition is true. + + """ + if not condition: + return + if not function is None: + function() + sys.stderr.write("PASSED\n") + sys.exit(0) + +class MatchError(object): + def __init__(self, message): + self.message = message + def __nonzero__(self): + return False + def __bool__(self): + return False + +def match_exact(lines=None, matches=None): + """ + Returns whether the given lists or strings containing lines separated + using newline characters contain exactly the same data. + + """ + if not type(lines) is list: + lines = lines.split("\n") + if not type(matches) is list: + matches = matches.split("\n") + if len(lines) != len(matches): + return + for i in range(len(lines)): + if lines[i] != matches[i]: + return MatchError("Mismatch at line %d\n- %s\n+ %s\n" % + (i+1, matches[i], lines[i])) + if len(lines) < len(matches): + return MatchError("Missing lines at line %d\n- %s" % + (len(lines), "\n- ".join(matches[len(lines):]))) + if len(lines) > len(matches): + return MatchError("Extra lines at line %d\n+ %s" % + (len(matches), "\n+ ".join(lines[len(matches):]))) + return 1 + + +def match_re(lines=None, res=None): + """ + Given lists or strings contain lines separated using newline characters. + This function matches those lines one by one, interpreting the lines in the + res parameter as regular expressions. + + """ + if not type(lines) is list: + lines = lines.split("\n") + if not type(res) is list: + res = res.split("\n") + for i in range(min(len(lines), len(res))): + if not re.compile("^" + res[i] + "$").search(lines[i]): + return MatchError("Mismatch at line %d\n- %s\n+ %s\n" % + (i+1, res[i], lines[i])) + if len(lines) < len(res): + return MatchError("Missing lines at line %d\n- %s" % + (len(lines), "\n- ".join(res[len(lines):]))) + if len(lines) > len(res): + return MatchError("Extra lines at line %d\n+ %s" % + (len(res), "\n+ ".join(lines[len(res):]))) + return 1 + + +class TestCmd: + def __init__(self, description=None, program=None, workdir=None, + subdir=None, verbose=False, match=None, inpath=None): + + self._cwd = os.getcwd() + self.description_set(description) + self.program_set(program, inpath) + self.verbose_set(verbose) + if match is None: + self.match_func = match_re + else: + self.match_func = match + self._dirlist = [] + self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0} + env = os.environ.get('PRESERVE') + if env: + self._preserve['pass_test'] = env + self._preserve['fail_test'] = env + self._preserve['no_result'] = env + else: + env = os.environ.get('PRESERVE_PASS') + if env is not None: + self._preserve['pass_test'] = env + env = os.environ.get('PRESERVE_FAIL') + if env is not None: + self._preserve['fail_test'] = env + env = os.environ.get('PRESERVE_PASS') + if env is not None: + self._preserve['PRESERVE_NO_RESULT'] = env + self._stdout = [] + self._stderr = [] + self.status = None + self.condition = 'no_result' + self.workdir_set(workdir) + self.subdir(subdir) + + def __del__(self): + self.cleanup() + + def __repr__(self): + return "%x" % id(self) + + def cleanup(self, condition=None): + """ + Removes any temporary working directories for the specified TestCmd + environment. If the environment variable PRESERVE was set when the + TestCmd environment was created, temporary working directories are not + removed. If any of the environment variables PRESERVE_PASS, + PRESERVE_FAIL or PRESERVE_NO_RESULT were set when the TestCmd + environment was created, then temporary working directories are not + removed if the test passed, failed or had no result, respectively. + Temporary working directories are also preserved for conditions + specified via the preserve method. + + Typically, this method is not called directly, but is used when the + script exits to clean up temporary working directories as appropriate + for the exit status. + + """ + if not self._dirlist: + return + if condition is None: + condition = self.condition + if self._preserve[condition]: + for dir in self._dirlist: + print("Preserved directory %s" % dir) + else: + list = self._dirlist[:] + list.reverse() + for dir in list: + self.writable(dir, 1) + shutil.rmtree(dir, ignore_errors=1) + + self._dirlist = [] + self.workdir = None + os.chdir(self._cwd) + try: + global _Cleanup + _Cleanup.remove(self) + except (AttributeError, ValueError): + pass + + def description_set(self, description): + """Set the description of the functionality being tested.""" + self.description = description + + def fail_test(self, condition=True, function=None, skip=0): + """Cause the test to fail.""" + if not condition: + return + self.condition = 'fail_test' + fail_test(self = self, + condition = condition, + function = function, + skip = skip) + + def match(self, lines, matches): + """Compare actual and expected file contents.""" + return self.match_func(lines, matches) + + def match_exact(self, lines, matches): + """Compare actual and expected file content exactly.""" + return match_exact(lines, matches) + + def match_re(self, lines, res): + """Compare file content with a regular expression.""" + return match_re(lines, res) + + def no_result(self, condition=True, function=None, skip=0): + """Report that the test could not be run.""" + if not condition: + return + self.condition = 'no_result' + no_result(self = self, + condition = condition, + function = function, + skip = skip) + + def pass_test(self, condition=True, function=None): + """Cause the test to pass.""" + if not condition: + return + self.condition = 'pass_test' + pass_test(self, condition, function) + + def preserve(self, *conditions): + """ + Arrange for the temporary working directories for the specified + TestCmd environment to be preserved for one or more conditions. If no + conditions are specified, arranges for the temporary working + directories to be preserved for all conditions. + + """ + if conditions is (): + conditions = ('pass_test', 'fail_test', 'no_result') + for cond in conditions: + self._preserve[cond] = 1 + + def program_set(self, program, inpath): + """Set the executable program or script to be tested.""" + if not inpath and program and not os.path.isabs(program[0]): + program[0] = os.path.join(self._cwd, program[0]) + self.program = program + + def read(self, file, mode='rb'): + """ + Reads and returns the contents of the specified file name. The file + name may be a list, in which case the elements are concatenated with + the os.path.join() method. The file is assumed to be under the + temporary working directory unless it is an absolute path name. The I/O + mode for the file may be specified and must begin with an 'r'. The + default is 'rb' (binary read). + + """ + if type(file) is list: + file = os.path.join(*file) + if not os.path.isabs(file): + file = os.path.join(self.workdir, file) + if mode[0] != 'r': + raise ValueError("mode must begin with 'r'") + return open(file, mode).read() + + def run(self, program=None, arguments=None, chdir=None, stdin=None, + universal_newlines=True): + """ + Runs a test of the program or script for the test environment. + Standard output and error output are saved for future retrieval via the + stdout() and stderr() methods. + + 'universal_newlines' parameter controls how the child process + input/output streams are opened as defined for the same named Python + subprocess.POpen constructor parameter. + + """ + if chdir: + if not os.path.isabs(chdir): + chdir = os.path.join(self.workpath(chdir)) + if self.verbose: + sys.stderr.write("chdir(" + chdir + ")\n") + else: + chdir = self.workdir + + cmd = [] + if program and program[0]: + if program[0] != self.program[0] and not os.path.isabs(program[0]): + program[0] = os.path.join(self._cwd, program[0]) + cmd += program + else: + cmd += self.program + if arguments: + cmd += arguments.split(" ") + if self.verbose: + sys.stderr.write(" ".join(cmd) + "\n") + p = subprocess.Popen(cmd, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=chdir, + universal_newlines=universal_newlines) + + if stdin: + if type(stdin) is list: + stdin = "".join(stdin) + out, err = p.communicate(stdin) + if not type(out) is str: + out = out.decode() + if not type(err) is str: + err = err.decode() + self._stdout.append(out) + self._stderr.append(err) + self.status = p.returncode + + if self.verbose: + sys.stdout.write(self._stdout[-1]) + sys.stderr.write(self._stderr[-1]) + + def stderr(self, run=None): + """ + Returns the error output from the specified run number. If there is + no specified run number, then returns the error output of the last run. + If the run number is less than zero, then returns the error output from + that many runs back from the current run. + + """ + if not run: + run = len(self._stderr) + elif run < 0: + run = len(self._stderr) + run + run -= 1 + if run < 0: + return '' + return self._stderr[run] + + def stdout(self, run=None): + """ + Returns the standard output from the specified run number. If there + is no specified run number, then returns the standard output of the + last run. If the run number is less than zero, then returns the + standard output from that many runs back from the current run. + + """ + if not run: + run = len(self._stdout) + elif run < 0: + run = len(self._stdout) + run + run -= 1 + if run < 0: + return '' + return self._stdout[run] + + def subdir(self, *subdirs): + """ + Create new subdirectories under the temporary working directory, one + for each argument. An argument may be a list, in which case the list + elements are concatenated using the os.path.join() method. + Subdirectories multiple levels deep must be created using a separate + argument for each level: + + test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory']) + + Returns the number of subdirectories actually created. + + """ + count = 0 + for sub in subdirs: + if sub is None: + continue + if type(sub) is list: + sub = os.path.join(*tuple(sub)) + new = os.path.join(self.workdir, sub) + try: + os.mkdir(new) + except: + pass + else: + count += 1 + return count + + def unlink(self, file): + """ + Unlinks the specified file name. The file name may be a list, in + which case the elements are concatenated using the os.path.join() + method. The file is assumed to be under the temporary working directory + unless it is an absolute path name. + + """ + if type(file) is list: + file = os.path.join(*tuple(file)) + if not os.path.isabs(file): + file = os.path.join(self.workdir, file) + os.unlink(file) + + def verbose_set(self, verbose): + """Set the verbose level.""" + self.verbose = verbose + + def workdir_set(self, path): + """ + Creates a temporary working directory with the specified path name. + If the path is a null string (''), a unique directory name is created. + + """ + if os.path.isabs(path): + self.workdir = path + else: + if path != None: + if path == '': + path = tempfile.mktemp() + if path != None: + os.mkdir(path) + self._dirlist.append(path) + global _Cleanup + try: + _Cleanup.index(self) + except ValueError: + _Cleanup.append(self) + # We would like to set self.workdir like this: + # self.workdir = path + # But symlinks in the path will report things differently from + # os.getcwd(), so chdir there and back to fetch the canonical + # path. + cwd = os.getcwd() + os.chdir(path) + self.workdir = os.getcwd() + os.chdir(cwd) + else: + self.workdir = None + + def workpath(self, *args): + """ + Returns the absolute path name to a subdirectory or file within the + current temporary working directory. Concatenates the temporary working + directory name with the specified arguments using os.path.join(). + + """ + return os.path.join(self.workdir, *tuple(args)) + + def writable(self, top, write): + """ + Make the specified directory tree writable (write == 1) or not + (write == None). + + """ + def _walk_chmod(arg, dirname, names): + st = os.stat(dirname) + os.chmod(dirname, arg(st[stat.ST_MODE])) + for name in names: + fullname = os.path.join(dirname, name) + st = os.stat(fullname) + os.chmod(fullname, arg(st[stat.ST_MODE])) + + _mode_writable = lambda mode: stat.S_IMODE(mode|0o200) + _mode_non_writable = lambda mode: stat.S_IMODE(mode&~0o200) + + if write: + f = _mode_writable + else: + f = _mode_non_writable + try: + for root, _, files in os.walk(top): + _walk_chmod(f, root, files) + except: + pass # Ignore any problems changing modes. + + def write(self, file, content, mode='wb'): + """ + Writes the specified content text (second argument) to the specified + file name (first argument). The file name may be a list, in which case + the elements are concatenated using the os.path.join() method. The file + is created under the temporary working directory. Any subdirectories in + the path must already exist. The I/O mode for the file may be specified + and must begin with a 'w'. The default is 'wb' (binary write). + + """ + if type(file) is list: + file = os.path.join(*tuple(file)) + if not os.path.isabs(file): + file = os.path.join(self.workdir, file) + if mode[0] != 'w': + raise ValueError("mode must begin with 'w'") + open(file, mode).write(content) diff --git a/src/boost/tools/build/test/TestToolset.py b/src/boost/tools/build/test/TestToolset.py new file mode 100644 index 00000000..fefa6c2e --- /dev/null +++ b/src/boost/tools/build/test/TestToolset.py @@ -0,0 +1,121 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates a toolset using a mock of the compiler + +import BoostBuild +import os +import re +import sys + +renames = {"debug": "variant=debug", "release": "variant=release"} + +def set_default_target_os(os): + global removed + global default_target_os + default_target_os = os + removed = set() + removed.add("target-os=" + default_target_os) + +def adjust_property(property): + global renames + if property in renames: + return renames[property] + else: + return property + +def adjust_properties(properties): + global removed + return [adjust_property(p) for p in properties if p not in removed] + +def has_property(name, properties): + return name in [re.sub("=.*", "", p) for p in properties] + +def get_property(name, properties): + for m in [re.match("(.*)=(.*)", p) for p in properties]: + if m and m.group(1) == name: + return m.group(2) + +def get_target_os(properties): + return get_property("target-os", properties) or default_target_os + +def expand_properties(properties): + result = properties[:] + if not has_property("variant", properties): + result += ["variant=debug"] + if not has_property("threading", properties): + result += ["threading=single"] + if not has_property("exception-handling", properties): + result += ["exception-handling=on"] + if not has_property("link", properties): + result += ["link=shared"] + if not has_property("rtti", properties): + result += ["rtti=on"] + if not has_property("runtime-link", properties): + result += ["runtime-link=shared"] + if not has_property("strip", properties): + result += ["strip=off"] + if not has_property("target-os", properties): + result += ["target-os=" + default_target_os] + return result + +def compute_path(properties, target_type): + path = "" + if "variant=release" in properties: + path += "/release" + else: + path += "/debug" + if has_property("address-model", properties): + path += "/address-model-" + get_property("address-model", properties) + if has_property("architecture", properties): + path += "/architecture-" + get_property("architecture", properties) + if "cxxstd=latest" in properties: + path += "/cxxstd-latest-iso" + if "exception-handling=off" in properties: + path += "/exception-handling-off" + if "link=static" in properties: + path += "/link-static" + if "rtti=off" in properties: + path += "/rtti-off" + if "runtime-link=static" in properties and target_type in ["exe"]: + path += "/runtime-link-static" + if "strip=on" in properties and target_type in ["dll", "exe", "obj2"]: + path += "/strip-on" + if get_target_os(properties) != default_target_os: + path += "/target-os-" + get_target_os(properties) + if "threading=multi" in properties: + path += "/threading-multi" + return path + +def test_toolset(toolset, version, property_sets): + t = BoostBuild.Tester() + + t.set_tree("toolset-mock") + + # Build necessary tools + t.run_build_system(["-sPYTHON_CMD=%s" % sys.executable], subdir="src") + set_default_target_os(t.read("src/bin/target-os.txt").strip()) + + for properties in property_sets: + t.set_toolset(toolset + "-" + version, get_target_os(properties)) + properties = adjust_properties(properties) + def path(t): + return toolset.split("-")[0] + "-*" + version + compute_path(properties, t) + os.environ["B2_PROPERTIES"] = " ".join(expand_properties(properties)) + t.run_build_system(["--user-config=", "-sPYTHON_CMD=%s" % sys.executable] + properties) + t.expect_addition("bin/%s/lib.obj" % (path("obj"))) + if "link=static" not in properties: + t.expect_addition("bin/%s/l1.dll" % (path("dll"))) + else: + t.expect_addition("bin/%s/l1.lib" % (path("lib"))) + t.expect_addition("bin/%s/main.obj" % (path("obj2"))) + t.expect_addition("bin/%s/test.exe" % (path("exe"))) + t.expect_nothing_more() + t.rm("bin") + + t.cleanup() diff --git a/src/boost/tools/build/test/abs_workdir.py b/src/boost/tools/build/test/abs_workdir.py new file mode 100644 index 00000000..fa6aadc5 --- /dev/null +++ b/src/boost/tools/build/test/abs_workdir.py @@ -0,0 +1,26 @@ +# Niklaus Giger, 2005-03-15 +# Testing whether we may run a test in absolute directories. There are no tests +# for temporary directories as this is implictly tested in a lot of other cases. + +# TODO: Move to a separate testing-system test group. +# TODO: Make the test not display any output on success. +# TODO: Make sure implemented path handling is correct under Windows, Cygwin & +# Unix/Linux. + +import BoostBuild +import os +import tempfile + +t = BoostBuild.Tester(["-ffile.jam"], workdir=os.getcwd(), pass_d0=False, + pass_toolset=False) + +t.write("file.jam", "EXIT [ PWD ] : 0 ;") + +t.run_build_system() +t.expect_output_lines("*%s*" % tempfile.gettempdir(), False) +t.expect_output_lines("*build/v2/test*") + +t.run_build_system(status=1, subdir="/must/fail/with/absolute/path", + stderr=None) + +t.cleanup() diff --git a/src/boost/tools/build/test/absolute_sources.py b/src/boost/tools/build/test/absolute_sources.py new file mode 100644 index 00000000..22ff1d08 --- /dev/null +++ b/src/boost/tools/build/test/absolute_sources.py @@ -0,0 +1,73 @@ +#!/usr/bin/python + +# Copyright 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that sources with absolute names are handled OK. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "path-constant TOP : . ;") +t.write("jamfile.jam", """\ +local pwd = [ PWD ] ; +ECHO $(pwd) XXXXX ; +exe hello : $(pwd)/hello.cpp $(TOP)/empty.cpp ; +""") +t.write("hello.cpp", "int main() {}\n") +t.write("empty.cpp", "\n") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.exe") +t.rm(".") + +# Test a contrived case in which an absolute name is used in a standalone +# project (not Jamfile). Moreover, the target with an absolute name is returned +# via an 'alias' and used from another project. +t.write("a.cpp", "int main() {}\n") +t.write("jamfile.jam", "exe a : /standalone//a ;") +t.write("jamroot.jam", "import standalone ;") +t.write("standalone.jam", """\ +import project ; +project.initialize $(__name__) ; +project standalone ; +local pwd = [ PWD ] ; +alias a : $(pwd)/a.cpp ; +""") + +t.write("standalone.py", """ +from b2.manager import get_manager + +# FIXME: this is ugly as death +get_manager().projects().initialize(__name__) + +import os ; + +# This use of list as parameter is also ugly. +project(['standalone']) + +pwd = os.getcwd() +alias('a', [os.path.join(pwd, 'a.cpp')]) +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") + +# Test absolute path in target ids. +t.rm(".") + +t.write("d1/jamroot.jam", "") +t.write("d1/jamfile.jam", "exe a : a.cpp ;") +t.write("d1/a.cpp", "int main() {}\n") +t.write("d2/jamroot.jam", "") +t.write("d2/jamfile.jam", """\ +local pwd = [ PWD ] ; +alias x : $(pwd)/../d1//a ; +""") + +t.run_build_system(subdir="d2") +t.expect_addition("d1/bin/$toolset/debug*/a.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/alias.py b/src/boost/tools/build/test/alias.py new file mode 100644 index 00000000..132e4c39 --- /dev/null +++ b/src/boost/tools/build/test/alias.py @@ -0,0 +1,107 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + + +############################################################################### +# +# test_alias_rule() +# ----------------- +# +############################################################################### + +def test_alias_rule(t): + """Basic alias rule test.""" + + t.write("jamroot.jam", """\ +exe a : a.cpp ; +exe b : b.cpp ; +exe c : c.cpp ; + +alias bin1 : a ; +alias bin2 : a b ; + +alias src : s.cpp ; +exe hello : hello.cpp src ; +""") + + t.write("a.cpp", "int main() {}\n") + t.copy("a.cpp", "b.cpp") + t.copy("a.cpp", "c.cpp") + t.copy("a.cpp", "hello.cpp") + t.write("s.cpp", "") + + # Check that targets to which "bin1" refers are updated, and only those. + t.run_build_system(["bin1"]) + t.expect_addition(BoostBuild.List("bin/$toolset/debug*/") * "a.exe a.obj") + t.expect_nothing_more() + + # Try again with "bin2" + t.run_build_system(["bin2"]) + t.expect_addition(BoostBuild.List("bin/$toolset/debug*/") * "b.exe b.obj") + t.expect_nothing_more() + + # Try building everything, making sure 'hello' target is created. + t.run_build_system() + t.expect_addition(BoostBuild.List("bin/$toolset/debug*/") * \ + "hello.exe hello.obj") + t.expect_addition("bin/$toolset/debug*/s.obj") + t.expect_addition(BoostBuild.List("bin/$toolset/debug*/") * "c.exe c.obj") + t.expect_nothing_more() + + +############################################################################### +# +# test_alias_source_usage_requirements() +# -------------------------------------- +# +############################################################################### + +def test_alias_source_usage_requirements(t): + """ + Check whether usage requirements are propagated via "alias". In case they + are not, linking will fail as there will be no main() function defined + anywhere in the source. + + """ + t.write("jamroot.jam", """\ +lib l : l.cpp : : : <define>WANT_MAIN ; +alias la : l ; +exe main : main.cpp la ; +""") + + t.write("l.cpp", """\ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +foo() {} +""") + + t.write("main.cpp", """\ +#ifdef WANT_MAIN +int main() {} +#endif +""") + + t.run_build_system() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +t = BoostBuild.Tester(use_test_config=False) + +test_alias_rule(t) +test_alias_source_usage_requirements(t) + +t.cleanup() diff --git a/src/boost/tools/build/test/alternatives.py b/src/boost/tools/build/test/alternatives.py new file mode 100644 index 00000000..7a52427d --- /dev/null +++ b/src/boost/tools/build/test/alternatives.py @@ -0,0 +1,129 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2003, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test main target alternatives. + +import BoostBuild +import string + +t = BoostBuild.Tester(use_test_config=False) + +# Test that basic alternatives selection works. +t.write("jamroot.jam", "") + +t.write("jamfile.jam", """ +exe a : a_empty.cpp ; +exe a : a.cpp : <variant>release ; +""") + +t.write("a_empty.cpp", "") + +t.write("a.cpp", "int main() {}\n") + +t.run_build_system(["release"]) + +t.expect_addition("bin/$toolset/release*/a.exe") + +# Test that alternative selection works for ordinary properties, in particular +# user-defined. +t.write("jamroot.jam", "") + +t.write("jamfile.jam", """ +import feature ; +feature.feature X : off on : propagated ; +exe a : b.cpp ; +exe a : a.cpp : <X>on ; +""") +t.write("b.cpp", "int main() {}\n") + +t.rm("bin") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/b.obj") + +t.run_build_system(["X=on"]) +t.expect_addition("bin/$toolset/debug/X-on*/a.obj") + +t.rm("bin") + +# Test that everything works ok even with the default build. +t.write("jamfile.jam", """\ +exe a : a_empty.cpp : <variant>release ; +exe a : a.cpp : <variant>debug ; +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") + +# Test that only properties which are in the build request matter for +# alternative selection. IOW, alternative with <variant>release is better than +# one with <variant>debug when building the release variant. +t.write("jamfile.jam", """\ +exe a : a_empty.cpp : <variant>debug ; +exe a : a.cpp : <variant>release ; +""") + +t.run_build_system(["release"]) +t.expect_addition("bin/$toolset/release*/a.exe") + +# Test that free properties do not matter. We really do not want <cxxflags> +# property in build request to affect alternative selection. +t.write("jamfile.jam", """ +exe a : a_empty.cpp : <variant>debug <define>FOO <include>BAR ; +exe a : a.cpp : <variant>release ; +""") + +t.rm("bin/$toolset/release/a.exe") +t.rm("bin/$toolset/release/*/a.exe") +t.run_build_system(["release", "define=FOO"]) +t.expect_addition("bin/$toolset/release*/a.exe") + +# Test that ambiguity is reported correctly. +t.write("jamfile.jam", """\ +exe a : a_empty.cpp ; +exe a : a.cpp ; +""") +t.run_build_system(["--no-error-backtrace"], status=None) +t.expect_output_lines("error: No best alternative for ./a") + +# Another ambiguity test: two matches properties in one alternative are neither +# better nor worse than a single one in another alternative. +t.write("jamfile.jam", """\ +exe a : a_empty.cpp : <optimization>off <profiling>off ; +exe a : a.cpp : <debug-symbols>on ; +""") + +t.run_build_system(["--no-error-backtrace"], status=None) +t.expect_output_lines("error: No best alternative for ./a") +t.rm("bin") + +# Test that we can have alternative without sources. +t.write("jamfile.jam", """\ +alias specific-sources ; +import feature ; +feature.extend os : MAGIC ; +alias specific-sources : b.cpp : <os>MAGIC ; +exe a : a.cpp specific-sources ; +""") +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") +t.rm("bin") + +# Test that subfeatures are expanded in alternatives +# and that unknown subfeatures fail to match instead of +# causing errors. +t.write("jamfile.jam", """\ +import feature : feature subfeature ; +feature X : off on : propagated ; +subfeature X on : version : 1 : propagated ; +exe a : a.cpp : <X>on-1 ; +exe a : a_empty.cpp ; +exe a : a_empty.cpp : <X>on-2 ; +""") +t.run_build_system(["X=on-1"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/always.py b/src/boost/tools/build/test/always.py new file mode 100644 index 00000000..95450346 --- /dev/null +++ b/src/boost/tools/build/test/always.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# Copyright 2016 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("main.cpp", """\ +int main() {} +""") + +t.write("Jamroot", """\ +exe test : main.cpp ; +always test ; +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/main.obj") +t.expect_addition("bin/$toolset/debug*/test.exe") +t.expect_nothing_more() + +t.run_build_system() +t.expect_touch("bin/$toolset/debug*/main.obj") +t.expect_touch("bin/$toolset/debug*/test.exe") +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/bad_dirname.py b/src/boost/tools/build/test/bad_dirname.py new file mode 100644 index 00000000..961a45a4 --- /dev/null +++ b/src/boost/tools/build/test/bad_dirname.py @@ -0,0 +1,22 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Regression test: when directory of project root contained regex +# metacharacters, Boost.Build failed to work. Bug reported by Michael Stevens. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("bad[abc]dirname/jamfile.jam", """ +""") + +t.write("bad[abc]dirname/jamroot.jam", """ +""") + +t.run_build_system(subdir="bad[abc]dirname") + +t.cleanup() diff --git a/src/boost/tools/build/test/boost-build.jam b/src/boost/tools/build/test/boost-build.jam new file mode 100644 index 00000000..668452da --- /dev/null +++ b/src/boost/tools/build/test/boost-build.jam @@ -0,0 +1,14 @@ +# Copyright 2002, 2003 Dave Abrahams +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Assume BOOST_BUILD_PATH point to the 'test' directory. +# We need to leave 'test' there, so that 'test-config.jam' +# can be found, but also add parent directory, to find +# all the other modules. + +BOOST_BUILD_PATH = $(BOOST_BUILD_PATH)/.. $(BOOST_BUILD_PATH) ; + +# Find the boost build system in the ../kernel directory. +boost-build ../src/kernel ; diff --git a/src/boost/tools/build/test/boostbook.py b/src/boost/tools/build/test/boostbook.py new file mode 100644 index 00000000..672d63da --- /dev/null +++ b/src/boost/tools/build/test/boostbook.py @@ -0,0 +1,23 @@ +#!/usr/bin/python + +# Copyright 2004, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import string + +t = BoostBuild.Tester() + +t.set_tree("boostbook") + +# For some reason, the messages are sent to stderr. +t.run_build_system() +t.fail_test(t.stdout().find("""Writing boost/A.html for refentry(boost.A) +Writing library/reference.html for section(library.reference) +Writing index.html for chapter(library) +Writing docs_HTML.manifest +""") == -1) +t.expect_addition(["html/boost/A.html", "html/index.html"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/boostbook/a.hpp b/src/boost/tools/build/test/boostbook/a.hpp new file mode 100644 index 00000000..5fab129a --- /dev/null +++ b/src/boost/tools/build/test/boostbook/a.hpp @@ -0,0 +1,16 @@ +/* Copyright 2004, 2006 Vladimir Prus */ +/* Distributed under the Boost Software License, Version 1.0. */ +/* (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) */ + + +// Seems like Boostbook does like classes outside of namespaces, +// and won't generate anything for them. +namespace boost { + +/// A class +class A { +public: + /// A constructor + A(); +}; +} diff --git a/src/boost/tools/build/test/boostbook/docs.xml b/src/boost/tools/build/test/boostbook/docs.xml new file mode 100644 index 00000000..c2d9b1f8 --- /dev/null +++ b/src/boost/tools/build/test/boostbook/docs.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" + "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> + +<!-- Copyright 2004 Vladimir Prus --> +<!-- Distributed under the Boost Software License, Version 1.0. --> +<!-- (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) --> + +<library + name="library" + dirname="librarys" id="library" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <libraryinfo> + <author> + <firstname>Joe</firstname> + <surname>Hacker</surname> + </author> + + <copyright> + <year>7002</year> + <holder>Joe Hacker</holder> + </copyright> + + </libraryinfo> + + <title>Documentation</title> + + <section> + <title>Introduction</title> + + <para>This is introduction</para> + + </section> + + <xi:include href="autodoc.xml"/> +</library> diff --git a/src/boost/tools/build/test/boostbook/jamroot.jam b/src/boost/tools/build/test/boostbook/jamroot.jam new file mode 100644 index 00000000..94564ca2 --- /dev/null +++ b/src/boost/tools/build/test/boostbook/jamroot.jam @@ -0,0 +1,3 @@ + +boostbook docs : docs.xml autodoc ; +doxygen autodoc : [ glob *.hpp ] ; diff --git a/src/boost/tools/build/test/build_dir.py b/src/boost/tools/build/test/build_dir.py new file mode 100644 index 00000000..3d1177bc --- /dev/null +++ b/src/boost/tools/build/test/build_dir.py @@ -0,0 +1,107 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that we can change build directory using the 'build-dir' project +# attribute. + +import BoostBuild +import string +import os + +t = BoostBuild.Tester(use_test_config=False) + + +# Test that top-level project can affect build dir. +t.write("jamroot.jam", "import gcc ;") +t.write("jamfile.jam", """\ +project : build-dir build ; +exe a : a.cpp ; +build-project src ; +""") + +t.write("a.cpp", "int main() {}\n") + +t.write("src/jamfile.jam", "exe b : b.cpp ; ") + +t.write("src/b.cpp", "int main() {}\n") + +t.run_build_system() + +t.expect_addition(["build/$toolset/debug*/a.exe", + "build/src/$toolset/debug*/b.exe"]) + +# Test that building from child projects work. +t.run_build_system(subdir='src') +t.ignore("build/config.log") +t.ignore("build/project-cache.jam") +t.expect_nothing_more() + +# Test that project can override build dir. +t.write("jamfile.jam", """\ +exe a : a.cpp ; +build-project src ; +""") + +t.write("src/jamfile.jam", """\ +project : build-dir build ; +exe b : b.cpp ; +""") + +t.run_build_system() +t.expect_addition(["bin/$toolset/debug*/a.exe", + "src/build/$toolset/debug*/b.exe"]) + +# Now test the '--build-dir' option. +t.rm(".") +t.write("jamroot.jam", "") + +# Test that we get an error when no project id is specified. +t.run_build_system(["--build-dir=foo"]) +t.fail_test(t.stdout().find( + "warning: the --build-dir option will be ignored") == -1) + +t.write("jamroot.jam", """\ +project foo ; +exe a : a.cpp ; +build-project sub ; +""") +t.write("a.cpp", "int main() {}\n") +t.write("sub/jamfile.jam", "exe b : b.cpp ;\n") +t.write("sub/b.cpp", "int main() {}\n") + +t.run_build_system(["--build-dir=build"]) +t.expect_addition(["build/foo/$toolset/debug*/a.exe", + "build/foo/sub/$toolset/debug*/b.exe"]) + +t.write("jamroot.jam", """\ +project foo : build-dir bin.v2 ; +exe a : a.cpp ; +build-project sub ; +""") + +t.run_build_system(["--build-dir=build"]) +t.expect_addition(["build/foo/bin.v2/$toolset/debug*/a.exe", + "build/foo/bin.v2/sub/$toolset/debug*/b.exe"]) + +# Try building in subdir. We expect that the entire build tree with be in +# 'sub/build'. Today, I am not sure if this is what the user expects, but let +# it be. +t.rm('build') +t.run_build_system(["--build-dir=build"], subdir="sub") +t.expect_addition(["sub/build/foo/bin.v2/sub/$toolset/debug*/b.exe"]) + +t.write("jamroot.jam", """\ +project foo : build-dir %s ; +exe a : a.cpp ; +build-project sub ; +""" % os.getcwd().replace('\\', '\\\\')) + +t.run_build_system(["--build-dir=build"], status=1) +t.fail_test(t.stdout().find( + "Absolute directory specified via 'build-dir' project attribute") == -1) + +t.cleanup() diff --git a/src/boost/tools/build/test/build_file.py b/src/boost/tools/build/test/build_file.py new file mode 100644 index 00000000..1ae86091 --- /dev/null +++ b/src/boost/tools/build/test/build_file.py @@ -0,0 +1,170 @@ +#!/usr/bin/python + +# Copyright (C) 2006. Vladimir Prus +# Copyright (C) 2008. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that we explicitly request a file (not target) to be built by +# specifying its name on the command line. + +import BoostBuild + + +############################################################################### +# +# test_building_file_from_specific_project() +# ------------------------------------------ +# +############################################################################### + +def test_building_file_from_specific_project(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +exe hello : hello.cpp ; +exe hello2 : hello.cpp ; +build-project sub ; +""") + t.write("hello.cpp", "int main() {}\n") + t.write("sub/jamfile.jam", """ +exe hello : hello.cpp ; +exe hello2 : hello.cpp ; +exe sub : hello.cpp ; +""") + t.write("sub/hello.cpp", "int main() {}\n") + + t.run_build_system(["sub", t.adjust_suffix("hello.obj")]) + t.expect_output_lines("*depends on itself*", False) + t.expect_addition("sub/bin/$toolset/debug*/hello.obj") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# test_building_file_from_specific_target() +# ----------------------------------------- +# +############################################################################### + +def test_building_file_from_specific_target(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +exe hello1 : hello1.cpp ; +exe hello2 : hello2.cpp ; +exe hello3 : hello3.cpp ; +""") + t.write("hello1.cpp", "int main() {}\n") + t.write("hello2.cpp", "int main() {}\n") + t.write("hello3.cpp", "int main() {}\n") + + t.run_build_system(["hello1", t.adjust_suffix("hello1.obj")]) + t.expect_addition("bin/$toolset/debug*/hello1.obj") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# test_building_missing_file_from_specific_target() +# ------------------------------------------------- +# +############################################################################### + +def test_building_missing_file_from_specific_target(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +exe hello1 : hello1.cpp ; +exe hello2 : hello2.cpp ; +exe hello3 : hello3.cpp ; +""") + t.write("hello1.cpp", "int main() {}\n") + t.write("hello2.cpp", "int main() {}\n") + t.write("hello3.cpp", "int main() {}\n") + + obj = t.adjust_suffix("hello2.obj") + t.run_build_system(["hello1", obj], status=1) + t.expect_output_lines("don't know how to make*" + obj) + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# test_building_multiple_files_with_different_names() +# --------------------------------------------------- +# +############################################################################### + +def test_building_multiple_files_with_different_names(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +exe hello1 : hello1.cpp ; +exe hello2 : hello2.cpp ; +exe hello3 : hello3.cpp ; +""") + t.write("hello1.cpp", "int main() {}\n") + t.write("hello2.cpp", "int main() {}\n") + t.write("hello3.cpp", "int main() {}\n") + + t.run_build_system([t.adjust_suffix("hello1.obj"), t.adjust_suffix( + "hello2.obj")]) + t.expect_addition("bin/$toolset/debug*/hello1.obj") + t.expect_addition("bin/$toolset/debug*/hello2.obj") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# test_building_multiple_files_with_the_same_name() +# ------------------------------------------------- +# +############################################################################### + +def test_building_multiple_files_with_the_same_name(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +exe hello : hello.cpp ; +exe hello2 : hello.cpp ; +build-project sub ; +""") + t.write("hello.cpp", "int main() {}\n") + t.write("sub/jamfile.jam", """ +exe hello : hello.cpp ; +exe hello2 : hello.cpp ; +exe sub : hello.cpp ; +""") + t.write("sub/hello.cpp", "int main() {}\n") + + t.run_build_system([t.adjust_suffix("hello.obj")]) + t.expect_output_lines("*depends on itself*", False) + t.expect_addition("bin/$toolset/debug*/hello.obj") + t.expect_addition("sub/bin/$toolset/debug*/hello.obj") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +test_building_file_from_specific_project() +test_building_file_from_specific_target() +test_building_missing_file_from_specific_target() +test_building_multiple_files_with_different_names() +test_building_multiple_files_with_the_same_name() diff --git a/src/boost/tools/build/test/build_hooks.py b/src/boost/tools/build/test/build_hooks.py new file mode 100644 index 00000000..9b8d37af --- /dev/null +++ b/src/boost/tools/build/test/build_hooks.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests add-pre-build-hook and add-post-build-hook + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("Jamroot.jam", """ +import build-system ; +build-system.add-pre-build-hook pre-build ; +build-system.add-post-build-hook post-build ; + +rule pre-build ( ) +{ + ECHO "in" pre-build hook ; +} + +rule post-build ( okay ? ) +{ + ECHO "in" post-build hook $(okay) ; +} + +message show : building main targets ; +""") + +t.run_build_system(stdout="""\ +building main targets +in pre-build hook +...found 1 target... +in post-build hook ok +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/build_no.py b/src/boost/tools/build/test/build_no.py new file mode 100644 index 00000000..771e697a --- /dev/null +++ b/src/boost/tools/build/test/build_no.py @@ -0,0 +1,23 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that <build>no property prevents a target from being built. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "exe hello : hello.cpp : <variant>debug:<build>no ;") +t.write("hello.cpp", "int main() {}\n") + +t.run_build_system() +t.expect_nothing_more() + +t.run_build_system(["release"]) +t.expect_addition("bin/$toolset/release*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/builtin_echo.py b/src/boost/tools/build/test/builtin_echo.py new file mode 100755 index 00000000..30923617 --- /dev/null +++ b/src/boost/tools/build/test/builtin_echo.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# Copyright 2012 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the ECHO rule. + +import BoostBuild + +def test_echo(name): + t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) + + t.write("file.jam", """\ +%s ; +UPDATE ; +""" % name) + t.run_build_system(stdout="\n") + + t.write("file.jam", """\ +%s a message ; +UPDATE ; +""" % name) + t.run_build_system(stdout="a message\n") + + t.cleanup() + +test_echo("ECHO") +test_echo("Echo") +test_echo("echo") diff --git a/src/boost/tools/build/test/builtin_exit.py b/src/boost/tools/build/test/builtin_exit.py new file mode 100755 index 00000000..1db86936 --- /dev/null +++ b/src/boost/tools/build/test/builtin_exit.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +# Copyright 2012 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the EXIT rule. + +import BoostBuild + +def test_exit(name): + t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) + + t.write("file.jam", "%s ;" % name) + t.run_build_system(status=1, stdout="\n") + t.rm(".") + + t.write("file.jam", "%s : 0 ;" % name) + t.run_build_system(stdout="\n") + t.rm(".") + + t.write("file.jam", "%s : 1 ;" % name) + t.run_build_system(status=1, stdout="\n") + t.rm(".") + + t.write("file.jam", "%s : 2 ;" % name) + t.run_build_system(status=2, stdout="\n") + t.rm(".") + + t.write("file.jam", "%s a message ;" % name) + t.run_build_system(status=1, stdout="a message\n") + t.rm(".") + + t.write("file.jam", "%s a message : 0 ;" % name) + t.run_build_system(stdout="a message\n") + t.rm(".") + + t.cleanup() + +test_exit("EXIT") +test_exit("Exit") +test_exit("exit") diff --git a/src/boost/tools/build/test/builtin_glob.py b/src/boost/tools/build/test/builtin_glob.py new file mode 100755 index 00000000..b68e7eeb --- /dev/null +++ b/src/boost/tools/build/test/builtin_glob.py @@ -0,0 +1,87 @@ +#!/usr/bin/python + +# Copyright 2014 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the GLOB rule. + +import os +import BoostBuild + +def test_glob(files, glob, expected, setup=""): + t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) + t.write("file.jam", setup + """ + for local p in [ SORT %s ] + { + ECHO $(p) ; + } + UPDATE ; + """ % glob) + for f in files: + t.write(f, "") + # convert / into \ on windows + expected = [os.path.join(*p.split("/")) for p in expected] + expected.sort() + t.run_build_system(stdout="\n".join(expected + [""])) + t.cleanup() + +# one or both arguments empty +test_glob([], "[ GLOB : ]", []) +test_glob([], "[ GLOB . : ]", []) +test_glob([], "[ GLOB : * ]", []) + +# a single result +test_glob([], "[ GLOB . : * ]", ["./file.jam"]) + +# * can match any number of characters +test_glob([], "[ GLOB . : file*.jam ]", ["./file.jam"]) +test_glob([], "[ GLOB . : f*am ]", ["./file.jam"]) +# ? should match a single character, but not more than one +test_glob([], "[ GLOB . : fi?e.?am ]", ["./file.jam"]) +test_glob([], "[ GLOB . : fi?.jam ]", []) +# [abc-fh-j] matches a set of characters +test_glob([], '[ GLOB . : "[f][i][l][e].jam" ]', ["./file.jam"]) +test_glob([], '[ GLOB . : "[fghau][^usdrwe][k-o][^f-s].jam" ]', ["./file.jam"]) +# \x matches x +test_glob([], "[ GLOB . : \\f\\i\\l\\e.jam ]", ["./file.jam"]) + +# multiple results +test_glob(["test.txt"], "[ GLOB . : * ]", ["./file.jam", "./test.txt"]) + +# directories +test_glob(["dir1/dir2/test.txt"], "[ GLOB dir1 : * ]", ["dir1/dir2"]); + +# non-existent directory +test_glob([], "[ GLOB dir1 : * ] ", []) + +# multiple directories and patterns +test_glob(["dir1/file1.txt", "dir2/file1.txt", + "dir2/file2.txt"], + "[ GLOB dir1 dir2 : file1* file2* ]", + ["dir1/file1.txt", "dir2/file1.txt", + "dir2/file2.txt"]) + +# The directory can contain . and .. +test_glob(["dir/test.txt"], "[ GLOB dir/. : test.txt ]", ["dir/./test.txt"]) +test_glob(["dir/test.txt"], "[ GLOB dir/.. : file.jam ]", ["dir/../file.jam"]) + +# On case insensitive filesystems, the result should +# be normalized. It should NOT be downcased. +test_glob(["TEST.TXT"], "[ GLOB . : TEST.TXT ]", ["./TEST.TXT"]) + +case_insensitive = (os.path.normcase("FILE") == "file") + +if case_insensitive: + test_glob(["TEST.TXT"], "[ GLOB . : test.txt ]", ["./TEST.TXT"]) + # This used to fail because the caching routines incorrectly + # reported that . and .. do not exist. + test_glob(["D1/D2/TEST.TXT"], "[ GLOB D1/./D2 : test.txt ]", + ["D1/./D2/TEST.TXT"]) + test_glob(["D1/TEST.TXT", "TEST.TXT"], "[ GLOB D1/../D1 : test.txt ]", + ["D1/../D1/TEST.TXT"]) + # This also failed because directories that were first found + # by GLOB were recorded as non-existent. + test_glob(["D1/D2/TEST.TXT"], "[ GLOB d1/d2 : test.txt ]", + ["D1/D2/TEST.TXT"], + "GLOB . : * ;") diff --git a/src/boost/tools/build/test/builtin_glob_archive.py b/src/boost/tools/build/test/builtin_glob_archive.py new file mode 100644 index 00000000..8cbc3be5 --- /dev/null +++ b/src/boost/tools/build/test/builtin_glob_archive.py @@ -0,0 +1,217 @@ +#!/usr/bin/python + +# Copyright 2014 Steven Watanabe +# Copyright 2015 Artur Shepilko +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the GLOB_ARCHIVE rule. + +import os +import sys +try: + from StringIO import StringIO +except: + from io import StringIO +import BoostBuild + +vms = ( os.name == 'posix' and sys.platform == 'OpenVMS') + +t = BoostBuild.Tester() + +## Setup test archive sources and symbols they contain. +sources = { + "a.cpp" : ["a"], + "b.cpp" : ["b"], + "b_match.cpp" : ["b_match"], + "c/nopath_check.cpp" : ["nopath_check"], + "CaseCheck.cpp" : ["CaseCheck"], + "seq_check1.cpp" : ["seq_check1"], + "seq_check2.cpp" : ["seq_check2"], + "seq_check3.cpp" : ["seq_check3"], + "symbols_check.c" : ["symbol", "symbol_match"], + "members_and_symbols_check.c" : ["member_and_symbol_match"], + "symbol_case_check.c" : ["SymbolCaseCheck"], + "main_check.cpp" : ["main"] +} + + +def create_sources(path, sources): + for s in sources : + f = os.path.join(path, s) + t.write(f, "") + output = StringIO() + for sym in sources[s] : + output.write("int %s() { return 0; }\n" % sym) + t.write(f, output.getvalue()) + + +def setup_archive(name, sources): + global archive + global obj_suffix + archive = t.adjust_names(name)[0] + obj_suffix = t.adjust_names(".obj")[0] + output = StringIO() + t.write("jamroot.jam","") + output.write("""\ +static-lib %s : +""" % name.split(".")[0]) + ## sort the sources, so we can test order of the globbed members + for s in sorted(sources) : + output.write("""\ + %s +""" % s) + output.write("""\ + ; +""") + t.write("lib/jamfile.jam", output.getvalue()) + create_sources("lib", sources) + t.run_build_system(subdir="lib") + built_archive = "lib/bin/$toolset/debug*/%s" % name + t.expect_addition(built_archive) + t.copy(built_archive, name) + t.rm("lib") + + +def test_glob_archive(archives, glob, expected, sort_results = False): + output = StringIO() + ## replace placeholders + glob = glob.replace("$archive1", archives[0]).replace("$obj", obj_suffix) + expected = [ m.replace("$archive1", + archives[0]).replace("$obj", obj_suffix) for m in expected ] + if len(archives) > 1 : + glob = glob.replace("$archive2", archives[1]).replace("$obj", obj_suffix) + expected = [ m.replace("$archive2", + archives[1]).replace("$obj", obj_suffix) for m in expected ] + ## create test jamfile + if sort_results : glob = "[ SORT %s ]" % glob + output.write("""\ + for local p in %s + { + ECHO $(p) ; + } + UPDATE ; + """ % glob) + t.write("file.jam", output.getvalue()) + ## run test jamfile and match against expected results + if sort_results : expected.sort() + t.run_build_system(["-ffile.jam"], stdout="\n".join(expected + [""])) + t.rm("file.jam") + + +## RUN TESTS +setup_archive("auxilliary1.lib", sources) +archive1 = archive +setup_archive("auxilliary2.lib", sources) +archive2 = archive + +## all arguments empty +test_glob_archive([archive1], "[ GLOB_ARCHIVE ]", []) + +## empty query +test_glob_archive([archive1], "[ GLOB_ARCHIVE $archive1 : ]", []) + +## no-match +test_glob_archive([archive1], "[ GLOB_ARCHIVE $archive1 : a ]", []) + +## match exact +test_glob_archive([archive1], "[ GLOB_ARCHIVE $archive1 : a$obj ]", + ["$archive1(a$obj)"]) + +## glob wildcards:1 +test_glob_archive([archive1], "[ GLOB_ARCHIVE $archive1 : b.* ]", + ["$archive1(b$obj)"]) + +## glob wildcards:2 +test_glob_archive([archive1], '[ GLOB_ARCHIVE $archive1 : "\\b?match[\.]*" ]', + ["$archive1(b_match$obj)"]) + +## glob wildcards:3 +test_glob_archive([archive1], "[ SORT [ GLOB_ARCHIVE $archive1 : b* ] ]", + ["$archive1(b$obj)", "$archive1(b_match$obj)"]) + +## glob multiple patterns with multiple results. +test_glob_archive([archive1], "[ SORT [ GLOB_ARCHIVE $archive1 : b.* b_* ] ]", + ["$archive1(b$obj)", "$archive1(b_match$obj)"]) + +## glob multiple archives and patterns. +test_glob_archive([archive1, archive2], + "[ SORT [ GLOB_ARCHIVE $archive1 $archive2 : b.* b_* ] ]", + ["$archive1(b$obj)", "$archive1(b_match$obj)", + "$archive2(b$obj)", "$archive2(b_match$obj)"]) + +## glob same archive multiple times. +test_glob_archive([archive1, archive1], + "[ GLOB_ARCHIVE $archive1 $archive2 $archive1 : b.* ]", + ["$archive1(b$obj)", "$archive2(b$obj)", "$archive1(b$obj)"]) + +## returned archive member has no path, even though its source object-file did. +## this is rather NT-specific, where members also store their object-file's path. +test_glob_archive([archive1], "[ GLOB_ARCHIVE $archive1 : nopath_check$obj ]", + ["$archive1(nopath_check$obj)"]) + +## case insensitive matching, when archives support case sensitive member names. +## VMS implementation forces case-insensitive matching and downcased member names. + +case_sensitive_members = ( not vms ) + +if case_sensitive_members: + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : casecheck$obj : true ]", + ["$archive1(CaseCheck$obj)"]) +elif vms: + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : CaseCheck$obj : false ]", + ["$archive1(casecheck$obj)"]) + + +## test the order of matched members, in general it should match the +## insertion sequence. +test_glob_archive([archive1], "[ SORT [ GLOB_ARCHIVE $archive1 : seq_check*$obj ] ]", + ["$archive1(seq_check1$obj)", "$archive1(seq_check2$obj)", + "$archive1(seq_check3$obj)"]) + + +## glob members by symbols they contain. +## Currently supported only on VMS. +symbol_glob_supported = ( vms ) + +if symbol_glob_supported : + ## NOTE: generated symbols are compiler-dependent and may be specifically + ## mangled (as in C++ case), so globbing by exact symbol is non-trivial. + ## However, C-generated symbols are likely to have more portable names, + ## so for the glob-by-symbol tests we glob C-generated archive members. + + ## glob members by exact symbol. + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : : : symbol ]", + ["$archive1(symbols_check$obj)"]) + + ## glob members by symbol wildcard. + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : : : symbol_* ]", + ["$archive1(symbols_check$obj)"]) + + ## glob members by member pattern AND symbol pattern. + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : *symbol* : : *member* ]", + ["$archive1(members_and_symbols_check$obj)"]) + + ## case insensitive symbol glob. + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : : true : symbolcasecheck ]", + ["$archive1(symbol_case_check$obj)"]) + + ## glob member that contains main symbol. + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : : : main _main ]", + ["$archive1(main_check$obj)"]) + +else: + test_glob_archive([archive1], + "[ GLOB_ARCHIVE $archive1 : : : symbol ]", + []) + + +t.cleanup() + diff --git a/src/boost/tools/build/test/builtin_readlink.py b/src/boost/tools/build/test/builtin_readlink.py new file mode 100755 index 00000000..e57d7286 --- /dev/null +++ b/src/boost/tools/build/test/builtin_readlink.py @@ -0,0 +1,24 @@ +#!/usr/bin/python + +# Copyright 2012 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("link-target", "") +os.symlink("link-target", "link") + +t.write("file.jam", """ +ECHO [ READLINK link ] ; +EXIT [ READLINK link-target ] : 0 ; +""") + +t.run_build_system(["-ffile.jam"], stdout="""link-target + +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/builtin_split_by_characters.py b/src/boost/tools/build/test/builtin_split_by_characters.py new file mode 100755 index 00000000..4a0a0e06 --- /dev/null +++ b/src/boost/tools/build/test/builtin_split_by_characters.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +# Copyright 2012. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# This tests the SPLIT_BY_CHARACTERS rule. + +import BoostBuild + +def test_invalid(params, expected_error_line): + t = BoostBuild.Tester(pass_toolset=0) + t.write("file.jam", "SPLIT_BY_CHARACTERS %s ;" % params) + t.run_build_system(["-ffile.jam"], status=1) + t.expect_output_lines("[*] %s" % expected_error_line) + t.cleanup() + +def test_valid(): + t = BoostBuild.Tester(pass_toolset=0) + t.write("jamroot.jam", """\ +import assert ; + +assert.result FooBarBaz : SPLIT_BY_CHARACTERS FooBarBaz : "" ; +assert.result FooBarBaz : SPLIT_BY_CHARACTERS FooBarBaz : x ; +assert.result FooBa Baz : SPLIT_BY_CHARACTERS FooBarBaz : r ; +assert.result FooBa Baz : SPLIT_BY_CHARACTERS FooBarBaz : rr ; +assert.result FooBa Baz : SPLIT_BY_CHARACTERS FooBarBaz : rrr ; +assert.result FooB rB z : SPLIT_BY_CHARACTERS FooBarBaz : a ; +assert.result FooB B z : SPLIT_BY_CHARACTERS FooBarBaz : ar ; +assert.result ooBarBaz : SPLIT_BY_CHARACTERS FooBarBaz : F ; +assert.result FooBarBa : SPLIT_BY_CHARACTERS FooBarBaz : z ; +assert.result ooBarBa : SPLIT_BY_CHARACTERS FooBarBaz : Fz ; +assert.result F B rB z : SPLIT_BY_CHARACTERS FooBarBaz : oa ; +assert.result Alib b : SPLIT_BY_CHARACTERS Alibaba : oa ; +assert.result libaba : SPLIT_BY_CHARACTERS Alibaba : oA ; +assert.result : SPLIT_BY_CHARACTERS FooBarBaz : FooBarBaz ; +assert.result : SPLIT_BY_CHARACTERS FooBarBaz : FoBarz ; + +# Questionable results - should they return an empty string or an empty list? +assert.result : SPLIT_BY_CHARACTERS "" : "" ; +assert.result : SPLIT_BY_CHARACTERS "" : x ; +assert.result : SPLIT_BY_CHARACTERS "" : r ; +assert.result : SPLIT_BY_CHARACTERS "" : rr ; +assert.result : SPLIT_BY_CHARACTERS "" : rrr ; +assert.result : SPLIT_BY_CHARACTERS "" : oa ; +""") + t.run_build_system() + t.cleanup() + +test_invalid("", "missing argument string") +test_invalid("Foo", "missing argument delimiters") +test_invalid(": Bar", "missing argument string") +test_invalid("a : b : c", "extra argument c") +test_invalid("a b : c", "extra argument b") +test_invalid("a : b c", "extra argument c") +test_valid() diff --git a/src/boost/tools/build/test/bzip2.py b/src/boost/tools/build/test/bzip2.py new file mode 100755 index 00000000..4e74c602 --- /dev/null +++ b/src/boost/tools/build/test/bzip2.py @@ -0,0 +1,119 @@ +#!/usr/bin/python + +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Build from source +t.write("bzip2/bzlib.h", 'bzip2') +t.write("bzip2/blocksort.c", 'blocksort') + +t.write("Jamroot.jam", """ +path-constant here : . ; +using bzip2 : : <source>$(here)/bzip2 ; +alias bzip2 : /bzip2//bzip2 : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, ''' +source_file('blocksort.c', 'blocksort') +action('-c -x c -I./bzip2 -o $blocksort.o $blocksort.c') +action('--dll $blocksort.o -o $bz2.so') +action('--archive $blocksort.o -o $bz2.a') +''') + +t.run_build_system() +t.expect_addition('bin/standalone/bzip2/mock/debug/bz2.dll') +t.expect_addition('bin/standalone/bzip2/mock/debug/link-static/bz2.lib') + +t.rm('bzip2') + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('bzlib.h.cpp', '#include <bzlib.h>\\n') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using bzip2 ; +exe test : test.cpp /bzip2//bzip2 : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=bz2 -o $config.exe') +action('-c -x c++ $bzlib.h.cpp -o $bzlib.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=bz2 -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using bzip2 ; +exe test : test.cpp /bzip2//bzip2 : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=bz2 -o $config.exe') +action('-c -x c++ $bzlib.h.cpp -o $bzlib.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=bz2 -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using bzip2 : : <name>mybzlib <include>$(here)/bzip2 <search>$(here)/bzip2 ; +exe test : test.cpp /bzip2//bzip2 : : <link>static <link>shared ; +""") + +t.write('bzip2/bzlib.h', 'bzip2') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./bzip2 --static-lib=mybzlib -o $config.exe') +action('-c -x c++ $test.cpp -I./bzip2 -o $test.o') +action('$test.o -L./bzip2 --static-lib=mybzlib -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using bzip2 : : <name>mybzlib <include>$(here)/bzip2 <search>$(here)/bzip2 ; +exe test : test.cpp /bzip2//bzip2 : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./bzip2 --shared-lib=mybzlib -o $config.exe') +action('-c -x c++ $test.cpp -I./bzip2 -o $test.o') +action('$test.o -L./bzip2 --shared-lib=mybzlib -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/c_file.py b/src/boost/tools/build/test/c_file.py new file mode 100644 index 00000000..85407d5f --- /dev/null +++ b/src/boost/tools/build/test/c_file.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that C files are compiled by a C compiler. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +project ; +exe hello : hello.cpp a.c ; +""") + +t.write("hello.cpp", """ +extern "C" int foo(); +int main() { return foo(); } +""") + +t.write("a.c", """ +// This will not compile unless in C mode. +int foo() +{ + int new = 0; + new = (new+1)*7; + return new; +} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/chain.py b/src/boost/tools/build/test/chain.py new file mode 100644 index 00000000..981e6ad1 --- /dev/null +++ b/src/boost/tools/build/test/chain.py @@ -0,0 +1,56 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests that : +# 1) the 'make' correctly assigns types to produced targets +# 2) if 'make' creates targets of type CPP, they are correctly used. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# In order to correctly link this app, 'b.cpp', created by a 'make' rule, should +# be compiled. + +t.write("jamroot.jam", "import gcc ;") + +t.write("jamfile.jam", r''' +import os ; +if [ os.name ] = NT +{ + actions create + { + echo int main() {} > $(<) + } +} +else +{ + actions create + { + echo "int main() {}" > $(<) + } +} + +IMPORT $(__name__) : create : : create ; + +exe a : l dummy.cpp ; + +# Needs to be a static lib for Windows - main() cannot appear in DLL. +static-lib l : a.cpp b.cpp ; + +make b.cpp : : create ; +''') + +t.write("a.cpp", "") + +t.write("dummy.cpp", "// msvc needs at least one object file\n") + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/a.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/clean.py b/src/boost/tools/build/test/clean.py new file mode 100644 index 00000000..dc72b924 --- /dev/null +++ b/src/boost/tools/build/test/clean.py @@ -0,0 +1,104 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("a.cpp", "int main() {}\n") +t.write("jamroot.jam", "exe a : a.cpp sub1//sub1 sub2//sub2 sub3//sub3 ;") +t.write("sub1/jamfile.jam", """\ +lib sub1 : sub1.cpp sub1_2 ../sub2//sub2 ; +lib sub1_2 : sub1_2.cpp ; +""") + +t.write("sub1/sub1.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub1() {} +""") + +t.write("sub1/sub1_2.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub1() {} +""") + +t.write("sub2/jamfile.jam", "lib sub2 : sub2.cpp ;") +t.write("sub2/sub2.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub2() {} +""") + +t.write("sub3/jamroot.jam", "lib sub3 : sub3.cpp ;") +t.write("sub3/sub3.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sub3() {} +""") + +# 'clean' should not remove files under separate jamroot.jam. +t.run_build_system() +t.run_build_system(["--clean"]) +t.expect_removal("bin/$toolset/debug*/a.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1_2.obj") +t.expect_removal("sub2/bin/$toolset/debug*/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug*/sub3.obj") + +# 'clean-all' removes everything it can reach. +t.run_build_system() +t.run_build_system(["--clean-all"]) +t.expect_removal("bin/$toolset/debug*/a.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1_2.obj") +t.expect_removal("sub2/bin/$toolset/debug*/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug*/sub3.obj") + +# 'clean' together with project target removes only under that project. +t.run_build_system() +t.run_build_system(["sub1", "--clean"]) +t.expect_nothing("bin/$toolset/debug*/a.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1_2.obj") +t.expect_nothing("sub2/bin/$toolset/debug*/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug*/sub3.obj") + +# 'clean-all' removes everything. +t.run_build_system() +t.run_build_system(["sub1", "--clean-all"]) +t.expect_nothing("bin/$toolset/debug*/a.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1.obj") +t.expect_removal("sub1/bin/$toolset/debug*/sub1_2.obj") +t.expect_removal("sub2/bin/$toolset/debug*/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug*/sub3.obj") + +# If main target is explicitly named, we should not remove files from other +# targets. +t.run_build_system() +t.run_build_system(["sub1//sub1", "--clean"]) +t.expect_removal("sub1/bin/$toolset/debug*/sub1.obj") +t.expect_nothing("sub1/bin/$toolset/debug*/sub1_2.obj") +t.expect_nothing("sub2/bin/$toolset/debug*/sub2.obj") +t.expect_nothing("sub3/bin/$toolset/debug*/sub3.obj") + +# Regression test: sources of the 'cast' rule were mistakenly deleted. +t.rm(".") +t.write("jamroot.jam", """\ +import cast ; +cast a cpp : a.h ; +""") +t.write("a.h", "") +t.run_build_system(["--clean"]) +t.expect_nothing("a.h") + +t.cleanup() diff --git a/src/boost/tools/build/test/cli_property_expansion.py b/src/boost/tools/build/test/cli_property_expansion.py new file mode 100644 index 00000000..24c82161 --- /dev/null +++ b/src/boost/tools/build/test/cli_property_expansion.py @@ -0,0 +1,41 @@ +#!/usr/bin/python + +# Copyright 2015 Aaron Boman +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that free property inside. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "") +t.write( + "subdir/build.jam", + """ + import feature ; + feature.feature my-feature : : free ; + """ +) +t.write( + "subdir/subsubdir/build.jam", + """ + exe hello : hello.c ; + """ +) +t.write( + "subdir/subsubdir/hello.c", + r""" + #include <stdio.h> + + int main(int argc, char **argv){ + printf("%s\n", "Hello, World!"); + } + """ +) + +# run from the root directory +t.run_build_system(['subdir/subsubdir', 'my-feature="some value"']) + +t.cleanup() diff --git a/src/boost/tools/build/test/collect_debug_info.py b/src/boost/tools/build/test/collect_debug_info.py new file mode 100755 index 00000000..27a66492 --- /dev/null +++ b/src/boost/tools/build/test/collect_debug_info.py @@ -0,0 +1,341 @@ +#!/usr/bin/python + +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Temporarily enabled dummy test that always fails and is used to collect +# extra debugging information from Boost Build test runner sites. + +import BoostBuild + +import os +import re +import sys + + +############################################################################### +# +# Public interface. +# +############################################################################### + +def collectDebugInfo(): + t = _init() + + global tag + + tag = "Python version" + try: + _info(sys.version) + except: + _info_exc() + + tag = "Python platform" + try: + _info(sys.platform) + except: + _info_exc() + + tag = "Boost Jam/Build version" + try: + _infoX(_getJamVersionInfo(t)) + except: + _info_exc() + + #_collectDebugInfo_environ() + + # Report prepared annotations. + t.fail_test(1, dump_difference=False, dump_stdio=False, dump_stack=False) + + +############################################################################### +# +# Private interface. +# +############################################################################### + +varSeparator = "###$^%~~~" + + +def _collect(results, prefix, name, t): + results.append("%s - %s - os.getenv(): %r" % (prefix, name, os.getenv( + name))) + results.append("%s - %s - os.environ.get(): %r" % (prefix, name, + os.environ.get(name))) + external_values = _getExternalValues(t, name) + results.append("%s - %s - external: %r" % (prefix, name, + external_values[name])) + + +def _collectDebugInfo_environ(t): + dummyVars = ["WOOF_WOOFIE_%d" % x for x in range(4)] + global tag + + tag = "XXX in os.environ" + try: + def f(name): + return "%s: %s" % (name, name in os.environ) + _infoX(f(x) for x in dummyVars) + except: + _info_exc() + + tag = "os.environ[XXX]" + try: + def f(name): + try: + result = os.environ[name] + except: + result = _str_exc() + return "%s: %r" % (name, result) + _infoX(f(x) for x in dummyVars) + except: + _info_exc() + + tag = "os.environ.get(XXX)" + try: + def f(name): + return "%s: %r" % (name, os.environ.get(name)) + _infoX(f(x) for x in dummyVars) + except: + _info_exc() + + tag = "os.getenv(XXX)" + try: + def f(name): + return "%s: %r" % (name, os.getenv(name)) + _infoX(f(x) for x in dummyVars) + except: + _info_exc() + + name = dummyVars[0] + value = "foo" + tag = "os.putenv(%s) to %r" % (name, value) + try: + results = [] + _collect(results, "before", name, t) + os.putenv(name, value) + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[1] + value = "bar" + tag = "os.environ[%s] to %r" % (name, value) + try: + results = [] + _collect(results, "before", name, t) + os.environ[name] = value + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[1] + value = "baz" + tag = "os.putenv(%s) to %r" % (name, value) + try: + results = [] + _collect(results, "before", name, t) + os.putenv(name, value) + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[1] + value = "" + tag = "os.putenv(%s) to %r" % (name, value) + try: + results = [] + _collect(results, "before", name, t) + os.putenv(name, value) + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[2] + value = "foo" + tag = "os.unsetenv(%s) from %r" % (name, value) + try: + results = [] + os.environ[name] = value + _collect(results, "before", name, t) + os.unsetenv(name) + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[2] + value = "foo" + tag = "del os.environ[%s] from %r" % (name, value) + try: + results = [] + os.environ[name] = value + _collect(results, "before", name, t) + del os.environ[name] + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[2] + value = "foo" + tag = "os.environ.pop(%s) from %r" % (name, value) + try: + results = [] + os.environ[name] = value + _collect(results, "before", name, t) + os.environ.pop(name) + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[2] + value1 = "foo" + value2 = "" + tag = "os.environ[%s] to %r from %r" % (name, value2, value1) + try: + results = [] + os.environ[name] = value1 + _collect(results, "before", name, t) + os.environ[name] = value2 + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + name = dummyVars[3] + value = '""' + tag = "os.environ[%s] to %r" % (name, value) + try: + results = [] + _collect(results, "before", name, t) + os.environ[name] = value + _collect(results, "after", name, t) + _infoX(results) + except: + _info_exc() + + +def _getExternalValues(t, *args): + t.run_build_system(["---var-name=%s" % x for x in args]) + result = dict() + for x in args: + m = re.search(r"^\*\*\*ENV\*\*\* %s: '(.*)' \*\*\*$" % x, t.stdout(), + re.MULTILINE) + if m: + result[x] = m.group(1) + else: + result[x] = None + return result + + +def _getJamVersionInfo(t): + result = [] + + # JAM version variables. + t.run_build_system(["---version"]) + for m in re.finditer(r"^\*\*\*VAR\*\*\* ([^:]*): (.*)\*\*\*$", t.stdout(), + re.MULTILINE): + name = m.group(1) + value = m.group(2) + if not value: + value = [] + elif value[-1] == ' ': + value = value[:-1].split(varSeparator) + else: + value = "!!!INVALID!!! - '%s'" % value + result.append("%s = %s" % (name, value)) + result.append("") + + # bjam -v output. + t.run_build_system(["-v"]) + result.append("--- output for 'bjam -v' ---") + result.append(t.stdout()) + + # bjam --version output. + t.run_build_system(["--version"], status=1) + result.append("--- output for 'bjam --version' ---") + result.append(t.stdout()) + + return result + + +def _init(): + toolsetName = "__myDummyToolset__" + + t = BoostBuild.Tester(["toolset=%s" % toolsetName], pass_toolset=False, + use_test_config=False) + + # Prepare a dummy toolset so we do not get errors in case the default one + # is not found. + t.write(toolsetName + ".jam", """\ +import feature ; +feature.extend toolset : %s ; +rule init ( ) { } +""" % toolsetName ) + + # Python version of the same dummy toolset. + t.write(toolsetName + ".py", """\ +from b2.build import feature +feature.extend('toolset', ['%s']) +def init(): pass +""" % toolsetName ) + + t.write("jamroot.jam", """\ +import os ; +.argv = [ modules.peek : ARGV ] ; +local names = [ MATCH ^---var-name=(.*) : $(.argv) ] ; +for x in $(names) +{ + value = [ os.environ $(x) ] ; + ECHO ***ENV*** $(x): '$(value)' *** ; +} +if ---version in $(.argv) +{ + for x in JAMVERSION JAM_VERSION JAMUNAME JAM_TIMESTAMP_RESOLUTION OS + { + v = [ modules.peek : $(x) ] ; + ECHO ***VAR*** $(x): "$(v:J=%s)" *** ; + } +} +""" % varSeparator) + + return t + + +def _info(*values): + values = list(values) + [""] + BoostBuild.annotation(tag, "\n".join(str(x) for x in values)) + + +def _infoX(values): + _info(*values) + + +def _info_exc(): + _info(_str_exc()) + + +def _str_exc(): + exc_type, exc_value = sys.exc_info()[0:2] + if exc_type is None: + exc_type_name = "None" + else: + exc_type_name = exc_type.__name__ + return "*** EXCEPTION *** %s - %s ***" % (exc_type_name, exc_value) + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +collectDebugInfo() diff --git a/src/boost/tools/build/test/command_line_properties.py b/src/boost/tools/build/test/command_line_properties.py new file mode 100644 index 00000000..518991b6 --- /dev/null +++ b/src/boost/tools/build/test/command_line_properties.py @@ -0,0 +1,166 @@ +#!/usr/bin/python + +import BoostBuild + +def test_basic(): + '''Tests that feature=value works''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + feature f1 : 1 2 ; + make output.txt : : @run ; + flags run OPTIONS <f1> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=2']) + t.expect_content("bin/*/output.txt", "2") + t.cleanup() + +def test_implicit(): + '''Tests that implicit features can be named without a feature''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + feature f1 : v1 v2 : implicit ; + make output.txt : : @run ; + flags run OPTIONS <f1> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['v2']) + t.expect_content("bin/*/output.txt", "v2") + t.cleanup() + +def test_optional(): + '''Tests that feature= works for optional features''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + feature f1 : 1 2 : optional ; + make output.txt : : @run ; + flags run OPTIONS <f1> ; + actions run { echo b $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=']) + t.expect_content("bin/*/output.txt", "b") + t.cleanup() + +def test_free(): + '''Free features named on the command line apply to all targets + everywhere. Free features can contain any characters, even those + that have a special meaning.''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + feature f1 : : free ; + make output1.txt : : @run : <dependency>output2.txt ; + make output2.txt : : @run ; + explicit output2.txt ; + flags run OPTIONS <f1> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=x,/:-']) + t.expect_content("bin*/output1.txt", "x,/:-") + t.expect_content("bin*/output2.txt", "x,/:-") + t.cleanup() + +def test_subfeature(): + '''Subfeatures should be expressed as feature=value-subvalue''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature subfeature ; + import toolset : flags ; + feature f1 : 1 2 ; + subfeature f1 2 : sub : x y ; + make output.txt : : @run ; + flags run OPTIONS <f1-2:sub> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=2-y']) + t.expect_content("bin/*/output.txt", "y") + t.cleanup() + +def test_multiple_values(): + '''Multiple values of a feature can be given in a comma-separated list''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + feature f1 : 1 2 3 ; + make output.txt : : @run ; + flags run OPTIONS <f1> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=2,3']) + t.expect_content("bin*/f1-2*/output.txt", "2") + t.expect_content("bin*/f1-3*/output.txt", "3") + t.cleanup() + +def test_multiple_properties(): + '''Multiple properties can be grouped with /''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + feature f1 : 1 2 ; + feature f2 : 3 4 ; + make output.txt : : @run ; + flags run OPTIONS <f1> ; + flags run OPTIONS <f2> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=2/f2=4']) + t.expect_content("bin/*/output.txt", "2 4") + t.cleanup() + +def test_cross_product(): + '''If multiple properties are specified on the command line + we expand to every possible maximum set of non-conflicting features. + This test should be run after testing individual components in + isolation.''' + t = BoostBuild.Tester() + t.write('Jamroot.jam', ''' + import feature : feature ; + import toolset : flags ; + # Make features symmetric to make the paths easier to distinguish + feature f1 : 11 12 13 14 15 : symmetric ; + feature f2 : 21 22 23 : symmetric ; + feature f3 : v1 v2 v3 v4 : implicit symmetric ; + feature f4 : : free ; + make output.txt : : @run ; + flags run OPTIONS <f1> ; + flags run OPTIONS <f2> ; + flags run OPTIONS <f3> ; + flags run OPTIONS <f4> ; + actions run { echo $(OPTIONS) > $(<) } + ''') + t.run_build_system(['f1=12,13/f2=22', 'v2', 'v3', 'f1=14', 'f2=23', + 'f4=xxx', 'f4=yyy', 'v4/f1=15/f4=zzz']) + t.expect_content("bin*/v2*/f1-12/f2-22*/output.txt", "12 22 v2 xxx yyy") + t.expect_addition("bin*/v2*/f1-12/f2-22*/output.txt") + t.expect_content("bin*/v2*/f1-13/f2-22*/output.txt", "13 22 v2 xxx yyy") + t.expect_addition("bin*/v2*/f1-13/f2-22*/output.txt") + t.expect_content("bin*/v2*/f1-14/f2-23*/output.txt", "14 23 v2 xxx yyy") + t.expect_addition("bin*/v2*/f1-14/f2-23*/output.txt") + t.expect_content("bin*/v3*/f1-12/f2-22*/output.txt", "12 22 v3 xxx yyy") + t.expect_addition("bin*/v3*/f1-12/f2-22*/output.txt") + t.expect_content("bin*/v3*/f1-13/f2-22*/output.txt", "13 22 v3 xxx yyy") + t.expect_addition("bin*/v3*/f1-13/f2-22*/output.txt") + t.expect_content("bin*/v3*/f1-14/f2-23*/output.txt", "14 23 v3 xxx yyy") + t.expect_addition("bin*/v3*/f1-14/f2-23*/output.txt") + t.expect_content("bin*/v4*/f1-15/f2-23*/output.txt", "15 23 v4 xxx yyy zzz") + t.expect_addition("bin*/v4*/f1-15/f2-23*/output.txt") + t.expect_nothing_more() + t.cleanup() + +test_basic() +test_implicit() +test_optional() +test_free() +test_subfeature() +test_multiple_values() +test_multiple_properties() +test_cross_product() diff --git a/src/boost/tools/build/test/composite.py b/src/boost/tools/build/test/composite.py new file mode 100644 index 00000000..e3a334b4 --- /dev/null +++ b/src/boost/tools/build/test/composite.py @@ -0,0 +1,25 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that composite properties are handled correctly. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +exe hello : hello.cpp : <variant>release ; +""") + +t.write("hello.cpp", """ +int main() {} +""") + +t.run_build_system() + +t.expect_addition("bin/$toolset/release*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/conditionals.py b/src/boost/tools/build/test/conditionals.py new file mode 100644 index 00000000..3ad36466 --- /dev/null +++ b/src/boost/tools/build/test/conditionals.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test conditional properties. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# Arrange a project which will build only if 'a.cpp' is compiled with "STATIC" +# define. +t.write("a.cpp", """\ +#ifdef STATIC +int main() {} +#endif +""") + +# Test conditionals in target requirements. +t.write("jamroot.jam", "exe a : a.cpp : <link>static:<define>STATIC ;") +t.run_build_system(["link=static"]) +t.expect_addition("bin/$toolset/debug/link-static*/a.exe") +t.rm("bin") + +# Test conditionals in project requirements. +t.write("jamroot.jam", """ +project : requirements <link>static:<define>STATIC ; +exe a : a.cpp ; +""") +t.run_build_system(["link=static"]) +t.expect_addition("bin/$toolset/debug/link-static*/a.exe") +t.rm("bin") + +# Regression test for a bug found by Ali Azarbayejani. Conditionals inside +# usage requirement were not being evaluated. +t.write("jamroot.jam", """ +lib l : l.cpp : : : <link>static:<define>STATIC ; +exe a : a.cpp l ; +""") +t.write("l.cpp", "int i;") +t.run_build_system(["link=static"]) +t.expect_addition("bin/$toolset/debug/link-static*/a.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/conditionals2.py b/src/boost/tools/build/test/conditionals2.py new file mode 100644 index 00000000..585e5ca7 --- /dev/null +++ b/src/boost/tools/build/test/conditionals2.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Regression test: it was possible that due to evaluation of conditional +# requirements, two different values of non-free features were present in a +# property set. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("a.cpp", "") + +t.write("jamroot.jam", """ +import feature ; +import common ; + +feature.feature the_feature : false true : propagated ; + +rule maker ( targets * : sources * : properties * ) +{ + if <the_feature>false in $(properties) && + <the_feature>true in $(properties) + { + EXIT "Oops, two different values of non-free feature" ; + } + CMD on $(targets) = [ common.file-creation-command ] ; +} + +actions maker +{ + $(CMD) $(<) ; +} + +make a : a.cpp : maker : <variant>debug:<the_feature>true ; +""") + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/conditionals3.py b/src/boost/tools/build/test/conditionals3.py new file mode 100644 index 00000000..feffe490 --- /dev/null +++ b/src/boost/tools/build/test/conditionals3.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that conditional properties work, even if property is free, and value +# includes a colon. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +exe hello : hello.cpp : <variant>debug:<define>"CLASS=Foo::Bar" ; +""") + +t.write("hello.cpp", """ +namespace Foo { class Bar { } ; } +int main() +{ + CLASS c; + c; // Disables the unused variable warning. +} +""") + +t.run_build_system(stdout=None, stderr=None) +t.expect_addition("bin/$toolset/debug*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/conditionals_multiple.py b/src/boost/tools/build/test/conditionals_multiple.py new file mode 100755 index 00000000..cb0cfa8c --- /dev/null +++ b/src/boost/tools/build/test/conditionals_multiple.py @@ -0,0 +1,312 @@ +#!/usr/bin/python + +# Copyright 2008 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that properties conditioned on more than one other property work as +# expected. + +import BoostBuild + + +############################################################################### +# +# test_multiple_conditions() +# -------------------------- +# +############################################################################### + +def test_multiple_conditions(): + """Basic tests for properties conditioned on multiple other properties.""" + + t = BoostBuild.Tester(["--user-config=", "--ignore-site-config", + "toolset=testToolset"], pass_toolset=False, use_test_config=False) + + t.write("testToolset.jam", """\ +import feature ; +feature.extend toolset : testToolset ; +rule init ( ) { } +""") + + t.write("testToolset.py", """\ +from b2.build import feature +feature.extend('toolset', ["testToolset"]) +def init ( ): pass +""") + + t.write("jamroot.jam", """\ +import feature ; +import notfile ; +import toolset ; + +feature.feature description : : free incidental ; +feature.feature aaa : 1 0 : incidental ; +feature.feature bbb : 1 0 : incidental ; +feature.feature ccc : 1 0 : incidental ; + +rule buildRule ( name : targets ? : properties * ) +{ + for local description in [ feature.get-values description : $(properties) ] + { + ECHO "description:" /$(description)/ ; + } +} + +notfile testTarget1 : @buildRule : : + <description>d + <aaa>0:<description>a0 + <aaa>1:<description>a1 + <aaa>0,<bbb>0:<description>a0-b0 + <aaa>0,<bbb>1:<description>a0-b1 + <aaa>1,<bbb>0:<description>a1-b0 + <aaa>1,<bbb>1:<description>a1-b1 + <aaa>0,<bbb>0,<ccc>0:<description>a0-b0-c0 + <aaa>0,<bbb>0,<ccc>1:<description>a0-b0-c1 + <aaa>0,<bbb>1,<ccc>1:<description>a0-b1-c1 + <aaa>1,<bbb>0,<ccc>1:<description>a1-b0-c1 + <aaa>1,<bbb>1,<ccc>0:<description>a1-b1-c0 + <aaa>1,<bbb>1,<ccc>1:<description>a1-b1-c1 ; +""") + + t.run_build_system(["aaa=1", "bbb=1", "ccc=1"]) + t.expect_output_lines("description: /d/" ) + t.expect_output_lines("description: /a0/" , False) + t.expect_output_lines("description: /a1/" ) + t.expect_output_lines("description: /a0-b0/" , False) + t.expect_output_lines("description: /a0-b1/" , False) + t.expect_output_lines("description: /a1-b0/" , False) + t.expect_output_lines("description: /a1-b1/" ) + t.expect_output_lines("description: /a0-b0-c0/", False) + t.expect_output_lines("description: /a0-b0-c1/", False) + t.expect_output_lines("description: /a0-b1-c1/", False) + t.expect_output_lines("description: /a1-b0-c1/", False) + t.expect_output_lines("description: /a1-b1-c0/", False) + t.expect_output_lines("description: /a1-b1-c1/" ) + + t.run_build_system(["aaa=0", "bbb=0", "ccc=1"]) + t.expect_output_lines("description: /d/" ) + t.expect_output_lines("description: /a0/" ) + t.expect_output_lines("description: /a1/" , False) + t.expect_output_lines("description: /a0-b0/" ) + t.expect_output_lines("description: /a0-b1/" , False) + t.expect_output_lines("description: /a1-b0/" , False) + t.expect_output_lines("description: /a1-b1/" , False) + t.expect_output_lines("description: /a0-b0-c0/", False) + t.expect_output_lines("description: /a0-b0-c1/" ) + t.expect_output_lines("description: /a0-b1-c1/", False) + t.expect_output_lines("description: /a1-b0-c1/", False) + t.expect_output_lines("description: /a1-b1-c0/", False) + t.expect_output_lines("description: /a1-b1-c1/", False) + + t.run_build_system(["aaa=0", "bbb=0", "ccc=0"]) + t.expect_output_lines("description: /d/" ) + t.expect_output_lines("description: /a0/" ) + t.expect_output_lines("description: /a1/" , False) + t.expect_output_lines("description: /a0-b0/" ) + t.expect_output_lines("description: /a0-b1/" , False) + t.expect_output_lines("description: /a1-b0/" , False) + t.expect_output_lines("description: /a1-b1/" , False) + t.expect_output_lines("description: /a0-b0-c0/" ) + t.expect_output_lines("description: /a0-b0-c1/", False) + t.expect_output_lines("description: /a0-b1-c1/", False) + t.expect_output_lines("description: /a1-b0-c1/", False) + t.expect_output_lines("description: /a1-b1-c0/", False) + t.expect_output_lines("description: /a1-b1-c1/", False) + + t.cleanup() + + +############################################################################### +# +# test_multiple_conditions_with_toolset_version() +# ----------------------------------------------- +# +############################################################################### + +def test_multiple_conditions_with_toolset_version(): + """ + Regression tests for properties conditioned on the toolset version + subfeature and some additional properties. + + """ + toolset = "testToolset" ; + + t = BoostBuild.Tester(["--user-config=", "--ignore-site-config"], + pass_toolset=False, use_test_config=False) + + t.write(toolset + ".jam", """\ +import feature ; +feature.extend toolset : %(toolset)s ; +feature.subfeature toolset %(toolset)s : version : 0 1 ; +rule init ( version ? ) { } +""" % {"toolset": toolset}) + + t.write("testToolset.py", """\ +from b2.build import feature +feature.extend('toolset', ["%(toolset)s"]) +feature.subfeature('toolset', "%(toolset)s", "version", ['0','1']) +def init (version=''): pass +""" % {"toolset": toolset}) + + t.write("jamroot.jam", """\ +import feature ; +import notfile ; +import toolset ; + +toolset.using testToolset ; + +feature.feature description : : free incidental ; +feature.feature aaa : 0 1 : incidental ; +feature.feature bbb : 0 1 : incidental ; +feature.feature ccc : 0 1 : incidental ; + +rule buildRule ( name : targets ? : properties * ) +{ + local ttt = [ feature.get-values toolset : $(properties) ] ; + local vvv = [ feature.get-values "toolset-testToolset:version" : $(properties) ] ; + local aaa = [ feature.get-values aaa : $(properties) ] ; + local bbb = [ feature.get-values bbb : $(properties) ] ; + local ccc = [ feature.get-values ccc : $(properties) ] ; + ECHO "toolset:" /$(ttt)/ "version:" /$(vvv)/ "aaa/bbb/ccc:" /$(aaa)/$(bbb)/$(ccc)/ ; + for local description in [ feature.get-values description : $(properties) ] + { + ECHO "description:" /$(description)/ ; + } +} + +notfile testTarget1 : @buildRule : : + <toolset>testToolset,<aaa>0:<description>t-a0 + <toolset>testToolset,<aaa>1:<description>t-a1 + + <toolset>testToolset-0,<aaa>0:<description>t0-a0 + <toolset>testToolset-0,<aaa>1:<description>t0-a1 + <toolset>testToolset-1,<aaa>0:<description>t1-a0 + <toolset>testToolset-1,<aaa>1:<description>t1-a1 + + <toolset>testToolset,<aaa>0,<bbb>0:<description>t-a0-b0 + <toolset>testToolset,<aaa>0,<bbb>1:<description>t-a0-b1 + <toolset>testToolset,<aaa>1,<bbb>0:<description>t-a1-b0 + <toolset>testToolset,<aaa>1,<bbb>1:<description>t-a1-b1 + + <aaa>0,<toolset>testToolset,<bbb>0:<description>a0-t-b0 + <aaa>0,<toolset>testToolset,<bbb>1:<description>a0-t-b1 + <aaa>1,<toolset>testToolset,<bbb>0:<description>a1-t-b0 + <aaa>1,<toolset>testToolset,<bbb>1:<description>a1-t-b1 + + <aaa>0,<bbb>0,<toolset>testToolset:<description>a0-b0-t + <aaa>0,<bbb>1,<toolset>testToolset:<description>a0-b1-t + <aaa>1,<bbb>0,<toolset>testToolset:<description>a1-b0-t + <aaa>1,<bbb>1,<toolset>testToolset:<description>a1-b1-t + + <toolset>testToolset-0,<aaa>0,<bbb>0:<description>t0-a0-b0 + <toolset>testToolset-0,<aaa>0,<bbb>1:<description>t0-a0-b1 + <toolset>testToolset-0,<aaa>1,<bbb>0:<description>t0-a1-b0 + <toolset>testToolset-0,<aaa>1,<bbb>1:<description>t0-a1-b1 + <toolset>testToolset-1,<aaa>0,<bbb>0:<description>t1-a0-b0 + <toolset>testToolset-1,<aaa>0,<bbb>1:<description>t1-a0-b1 + <toolset>testToolset-1,<aaa>1,<bbb>0:<description>t1-a1-b0 + <toolset>testToolset-1,<aaa>1,<bbb>1:<description>t1-a1-b1 + + <aaa>0,<toolset>testToolset-1,<bbb>0:<description>a0-t1-b0 + <aaa>0,<toolset>testToolset-1,<bbb>1:<description>a0-t1-b1 + <aaa>1,<toolset>testToolset-0,<bbb>0:<description>a1-t0-b0 + <aaa>1,<toolset>testToolset-0,<bbb>1:<description>a1-t0-b1 + + <bbb>0,<aaa>1,<toolset>testToolset-0:<description>b0-a1-t0 + <bbb>0,<aaa>0,<toolset>testToolset-1:<description>b0-a0-t1 + <bbb>0,<aaa>1,<toolset>testToolset-1:<description>b0-a1-t1 + <bbb>1,<aaa>0,<toolset>testToolset-1:<description>b1-a0-t1 + <bbb>1,<aaa>1,<toolset>testToolset-0:<description>b1-a1-t0 + <bbb>1,<aaa>1,<toolset>testToolset-1:<description>b1-a1-t1 ; +""") + + t.run_build_system(["aaa=1", "bbb=1", "ccc=1", "toolset=%s-0" % toolset]) + t.expect_output_lines("description: /t-a0/" , False) + t.expect_output_lines("description: /t-a1/" ) + t.expect_output_lines("description: /t0-a0/" , False) + t.expect_output_lines("description: /t0-a1/" ) + t.expect_output_lines("description: /t1-a0/" , False) + t.expect_output_lines("description: /t1-a1/" , False) + t.expect_output_lines("description: /t-a0-b0/" , False) + t.expect_output_lines("description: /t-a0-b1/" , False) + t.expect_output_lines("description: /t-a1-b0/" , False) + t.expect_output_lines("description: /t-a1-b1/" ) + t.expect_output_lines("description: /a0-t-b0/" , False) + t.expect_output_lines("description: /a0-t-b1/" , False) + t.expect_output_lines("description: /a1-t-b0/" , False) + t.expect_output_lines("description: /a1-t-b1/" ) + t.expect_output_lines("description: /a0-b0-t/" , False) + t.expect_output_lines("description: /a0-b1-t/" , False) + t.expect_output_lines("description: /a1-b0-t/" , False) + t.expect_output_lines("description: /a1-b1-t/" ) + t.expect_output_lines("description: /t0-a0-b0/", False) + t.expect_output_lines("description: /t0-a0-b1/", False) + t.expect_output_lines("description: /t0-a1-b0/", False) + t.expect_output_lines("description: /t0-a1-b1/" ) + t.expect_output_lines("description: /t1-a0-b0/", False) + t.expect_output_lines("description: /t1-a0-b1/", False) + t.expect_output_lines("description: /t1-a1-b0/", False) + t.expect_output_lines("description: /t1-a1-b1/", False) + t.expect_output_lines("description: /a0-t1-b0/", False) + t.expect_output_lines("description: /a0-t1-b1/", False) + t.expect_output_lines("description: /a1-t0-b0/", False) + t.expect_output_lines("description: /a1-t0-b1/" ) + t.expect_output_lines("description: /b0-a1-t0/", False) + t.expect_output_lines("description: /b0-a0-t1/", False) + t.expect_output_lines("description: /b0-a1-t1/", False) + t.expect_output_lines("description: /b1-a0-t1/", False) + t.expect_output_lines("description: /b1-a1-t0/" ) + t.expect_output_lines("description: /b1-a1-t1/", False) + + t.run_build_system(["aaa=1", "bbb=1", "ccc=1", "toolset=%s-1" % toolset]) + t.expect_output_lines("description: /t-a0/" , False) + t.expect_output_lines("description: /t-a1/" ) + t.expect_output_lines("description: /t0-a0/" , False) + t.expect_output_lines("description: /t0-a1/" , False) + t.expect_output_lines("description: /t1-a0/" , False) + t.expect_output_lines("description: /t1-a1/" ) + t.expect_output_lines("description: /t-a0-b0/" , False) + t.expect_output_lines("description: /t-a0-b1/" , False) + t.expect_output_lines("description: /t-a1-b0/" , False) + t.expect_output_lines("description: /t-a1-b1/" ) + t.expect_output_lines("description: /a0-t-b0/" , False) + t.expect_output_lines("description: /a0-t-b1/" , False) + t.expect_output_lines("description: /a1-t-b0/" , False) + t.expect_output_lines("description: /a1-t-b1/" ) + t.expect_output_lines("description: /a0-b0-t/" , False) + t.expect_output_lines("description: /a0-b1-t/" , False) + t.expect_output_lines("description: /a1-b0-t/" , False) + t.expect_output_lines("description: /a1-b1-t/" ) + t.expect_output_lines("description: /t0-a0-b0/", False) + t.expect_output_lines("description: /t0-a0-b1/", False) + t.expect_output_lines("description: /t0-a1-b0/", False) + t.expect_output_lines("description: /t0-a1-b1/", False) + t.expect_output_lines("description: /t1-a0-b0/", False) + t.expect_output_lines("description: /t1-a0-b1/", False) + t.expect_output_lines("description: /t1-a1-b0/", False) + t.expect_output_lines("description: /t1-a1-b1/" ) + t.expect_output_lines("description: /a0-t1-b0/", False) + t.expect_output_lines("description: /a0-t1-b1/", False) + t.expect_output_lines("description: /a1-t0-b0/", False) + t.expect_output_lines("description: /a1-t0-b1/", False) + t.expect_output_lines("description: /b0-a1-t0/", False) + t.expect_output_lines("description: /b0-a0-t1/", False) + t.expect_output_lines("description: /b0-a1-t1/", False) + t.expect_output_lines("description: /b1-a0-t1/", False) + t.expect_output_lines("description: /b1-a1-t0/", False) + t.expect_output_lines("description: /b1-a1-t1/" ) + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +test_multiple_conditions() +test_multiple_conditions_with_toolset_version() diff --git a/src/boost/tools/build/test/configuration.py b/src/boost/tools/build/test/configuration.py new file mode 100755 index 00000000..2123a4fe --- /dev/null +++ b/src/boost/tools/build/test/configuration.py @@ -0,0 +1,397 @@ +#!/usr/bin/python + +# Copyright 2008, 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test Boost Build configuration file handling. + +import BoostBuild +import TestCmd + +import os +import os.path +import re + + +############################################################################### +# +# test_user_configuration() +# ------------------------- +# +############################################################################### + +def test_user_configuration(): + """ + Test Boost Build user configuration handling. Both relative and absolute + path handling is tested. + + """ + + implicitConfigLoadMessage = \ + "notice: Loading user-config configuration file: *" + explicitConfigLoadMessage = \ + "notice: Loading explicitly specified user configuration file:" + disabledConfigLoadMessage = \ + "notice: User configuration file loading explicitly disabled." + testMessage = "_!_!_!_!_!_!_!_!_ %s _!_!_!_!_!_!_!_!_" + toolsetName = "__myDummyToolset__" + subdirName = "ASubDirectory" + configFileNames = ["ups_lala_1.jam", "ups_lala_2.jam", + os.path.join(subdirName, "ups_lala_3.jam")] + + t = BoostBuild.Tester(["toolset=%s" % toolsetName, + "--debug-configuration"], pass_toolset=False, use_test_config=False) + + for configFileName in configFileNames: + message = "ECHO \"%s\" ;" % testMessage % configFileName + # We need to double any backslashes in the message or Jam will + # interpret them as escape characters. + t.write(configFileName, message.replace("\\", "\\\\")) + + # Prepare a dummy toolset so we do not get errors in case the default one + # is not found. + t.write(toolsetName + ".jam", """\ +import feature ; +feature.extend toolset : %s ; +rule init ( ) { } +""" % toolsetName) + + # Python version of the same dummy toolset. + t.write(toolsetName + ".py", """\ +from b2.build import feature +feature.extend('toolset', ['%s']) +def init(): pass +""" % toolsetName) + + t.write("jamroot.jam", """\ +local test-index = [ MATCH ---test-id---=(.*) : [ modules.peek : ARGV ] ] ; +ECHO test-index: $(test-index:E=(unknown)) ; +""") + + class LocalTester: + def __init__(self, tester): + self.__tester = tester + self.__test_ids = [] + + def __assertionFailure(self, message): + BoostBuild.annotation("failure", "Internal test assertion failure " + "- %s" % message) + self.__tester.fail_test(1) + + def __call__(self, test_id, env, extra_args=None, *args, **kwargs): + if env == "" and not canSetEmptyEnvironmentVariable: + self.__assertionFailure("Can not set empty environment " + "variables on this platform.") + self.__registerTestId(str(test_id)) + if extra_args is None: + extra_args = [] + extra_args.append("---test-id---=%s" % test_id) + env_name = "BOOST_BUILD_USER_CONFIG" + previous_env = os.environ.get(env_name) + _env_set(env_name, env) + try: + self.__tester.run_build_system(extra_args, *args, **kwargs) + finally: + _env_set(env_name, previous_env) + + def __registerTestId(self, test_id): + if test_id in self.__test_ids: + self.__assertionFailure("Multiple test cases encountered " + "using the same test id '%s'." % test_id) + self.__test_ids.append(test_id) + + test = LocalTester(t) + + test(1, None) + t.expect_output_lines(explicitConfigLoadMessage, False) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(2, None, ["--user-config="]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage, False) + t.expect_output_lines(disabledConfigLoadMessage) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(3, None, ['--user-config=""']) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage, False) + t.expect_output_lines(disabledConfigLoadMessage) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(4, None, ['--user-config="%s"' % configFileNames[0]]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0]) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(5, None, ['--user-config="%s"' % configFileNames[2]]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2]) + + test(6, None, ['--user-config="%s"' % os.path.abspath(configFileNames[1])]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1]) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(7, None, ['--user-config="%s"' % os.path.abspath(configFileNames[2])]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2]) + + if canSetEmptyEnvironmentVariable: + test(8, "") + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage, False) + t.expect_output_lines(disabledConfigLoadMessage, True) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(9, '""') + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage, False) + t.expect_output_lines(disabledConfigLoadMessage) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(10, configFileNames[1]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1]) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(11, configFileNames[1], ['--user-config=""']) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage, False) + t.expect_output_lines(disabledConfigLoadMessage) + t.expect_output_lines(testMessage % configFileNames[0], False) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(12, configFileNames[1], ['--user-config="%s"' % configFileNames[0]]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0]) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + if canSetEmptyEnvironmentVariable: + test(13, "", ['--user-config="%s"' % configFileNames[0]]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0]) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(14, '""', ['--user-config="%s"' % configFileNames[0]]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0]) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + test(15, "invalid", ['--user-config="%s"' % configFileNames[0]]) + t.expect_output_lines(implicitConfigLoadMessage, False) + t.expect_output_lines(explicitConfigLoadMessage) + t.expect_output_lines(disabledConfigLoadMessage, False) + t.expect_output_lines(testMessage % configFileNames[0]) + t.expect_output_lines(testMessage % configFileNames[1], False) + t.expect_output_lines(testMessage % configFileNames[2], False) + + t.cleanup() + + +############################################################################### +# +# Private interface. +# +############################################################################### + +def _canSetEmptyEnvironmentVariable(): + """ + Unfortunately different OSs (and possibly Python implementations as well) + have different interpretations of what it means to set an environment + variable to an empty string. Some (e.g. Windows) interpret it as unsetting + the variable and some (e.g. AIX or Darwin) actually set it to an empty + string. + + """ + dummyName = "UGNABUNGA_FOO_BAR_BAZ_FEE_FAE_FOU_FAM" + original = os.environ.get(dummyName) + _env_set(dummyName, "") + result = _getExternalEnv(dummyName) == "" + _env_set(dummyName, original) + return result + + +def _env_del(name): + """ + Unsets the given environment variable if it is currently set. + + Note that we can not use os.environ.pop() or os.environ.clear() here + since prior to Python 2.6 these functions did not remove the actual + environment variable by calling os.unsetenv(). + + """ + try: + del os.environ[name] + except KeyError: + pass + + +def _env_set(name, value): + """ + Sets the given environment variable value or unsets it, if the value is + None. + + """ + if value is None: + _env_del(name) + else: + os.environ[name] = value + + +def _getExternalEnv(name): + toolsetName = "__myDummyToolset__" + + t = BoostBuild.Tester(["toolset=%s" % toolsetName], pass_toolset=False, + use_test_config=False) + try: + # Prepare a dummy toolset so we do not get errors in case the default + # one is not found. + t.write(toolsetName + ".jam", """\ +import feature ; +feature.extend toolset : %s ; +rule init ( ) { } +""" % toolsetName) + + # Python version of the same dummy toolset. + t.write(toolsetName + ".py", """\ +from b2.build import feature +feature.extend('toolset', ['%s']) +def init(): pass +""" % toolsetName) + + t.write("jamroot.jam", """\ +import os ; +local names = [ MATCH ^---var-name---=(.*) : [ modules.peek : ARGV ] ] ; +for x in $(names) +{ + value = [ os.environ $(x) ] ; + ECHO "###" $(x): '$(value)' "###" ; +} +""") + + t.run_build_system(["---var-name---=%s" % name]) + m = re.search("^### %s: '(.*)' ###$" % name, t.stdout(), re.MULTILINE) + if m: + return m.group(1) + finally: + t.cleanup() + + +def test_site_config(): + # Ignore user-config, just in case it depends on the user's site-config.jam + t = BoostBuild.Tester(["--user-config="], use_test_config=False, + pass_toolset=0) + # We can immediately exit after we finish loading the config files + t.write("Jamroot", "EXIT Done : 0 ;") + t.write("my-site-config.jam", "ECHO Loaded my-site-config ;") + + t.run_build_system(["--site-config=my-site-config.jam"], + stdout="Loaded my-site-config\nDone\n") + + t.run_build_system(["--ignore-site-config", "--debug-configuration"]) + t.expect_output_lines("""\ +notice: Site configuration files will be ignored due to the +notice: --ignore-site-config command-line option.""") + + t.run_build_system(["--site-config=", "--debug-configuration"]) + t.expect_output_lines("""\ +notice: Site configuration file loading explicitly disabled.""") + + t.cleanup() + +def test_global_config(): + t = BoostBuild.Tester(use_test_config=False, pass_toolset=0) + t.write("my-config.jam", "ECHO Loading my-config ;") + t.write("Jamroot", "EXIT Done : 0 ;") + t.write("project-config.jam", "ECHO bad ;") + t.run_build_system(["--config=my-config.jam", "--debug-configuration"], + match=TestCmd.match_re, stdout= +r"""notice: found boost-build\.jam at .* +notice: loading Boost\.Build from .* +notice: Searching '.*' for all-config configuration file 'my-config\.jam'\. +notice: Loading all-config configuration file 'my-config\.jam' from '.*'\. +Loading my-config +notice: Regular configuration files will be ignored due +notice: to the global configuration being loaded\. +Done +""") + t.run_build_system(["--config=", "--debug-configuration"], + match=TestCmd.match_re, stdout= +r"""notice: found boost-build\.jam at .* +notice: loading Boost\.Build from .* +notice: Configuration file loading explicitly disabled. +Done +""") + t.cleanup() + +def test_project_config(): + t = BoostBuild.Tester(["--user-config=", "--site-config="], + use_test_config=False, pass_toolset=False) + t.write("Jamroot", "EXIT Done : 0 ;") + t.write("project-config.jam", "ECHO Loading Root ;") + t.write("my-project-config.jam", "ECHO Loading explicit ;") + t.write("sub/project-config.jam", "ECHO Loading subdir ;") + t.write("sub/Jamfile", "") + + t.run_build_system(stdout="Loading Root\nDone\n") + t.run_build_system(subdir="sub", stdout="Loading subdir\nDone\n") + t.rm("sub/project-config.jam") + t.run_build_system(subdir="sub", stdout="Loading Root\nDone\n") + t.run_build_system(["--project-config=my-project-config.jam"], + stdout="Loading explicit\nDone\n") + + t.cleanup() + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +canSetEmptyEnvironmentVariable = _canSetEmptyEnvironmentVariable() + +test_user_configuration() +test_site_config() +test_global_config() +test_project_config() diff --git a/src/boost/tools/build/test/configure.py b/src/boost/tools/build/test/configure.py new file mode 100644 index 00000000..9e47af2e --- /dev/null +++ b/src/boost/tools/build/test/configure.py @@ -0,0 +1,267 @@ +#!/usr/bin/python + +# Copyright 2017 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests configure.check-target-builds and friends + +import BoostBuild + +def test_check_target_builds(): + t = BoostBuild.Tester(use_test_config=0) + t.write("Jamroot", """ +import configure ; +obj pass : pass.cpp ; +obj fail : fail.cpp ; +explicit pass fail ; +obj foo : foo.cpp : + [ configure.check-target-builds pass : <define>PASS : <define>FAIL ] ; +obj bar : foo.cpp : + [ configure.check-target-builds fail : <define>FAIL : <define>PASS ] ; +""") + t.write("pass.cpp", "void f() {}\n") + t.write("fail.cpp", "#error fail.cpp\n") + t.write("foo.cpp", """ +#ifndef PASS +#error PASS not defined +#endif +#ifdef FAIL +#error FAIL is defined +#endif +""") + t.run_build_system() + t.expect_output_lines([ + " - pass builds : yes", + " - fail builds : no"]) + t.expect_addition("bin/$toolset/debug*/pass.obj") + t.expect_addition("bin/$toolset/debug*/foo.obj") + t.expect_addition("bin/$toolset/debug*/bar.obj") + t.expect_nothing_more() + + # An up-to-date build should use the cache + t.run_build_system() + t.expect_output_lines([ + " - pass builds : yes (cached)", + " - fail builds : no (cached)"]) + t.expect_nothing_more() + + # -a should re-run everything, including configuration checks + t.run_build_system(["-a"]) + t.expect_output_lines([ + " - pass builds : yes", + " - fail builds : no"]) + t.expect_touch("bin/$toolset/debug*/pass.obj") + t.expect_touch("bin/$toolset/debug*/foo.obj") + t.expect_touch("bin/$toolset/debug*/bar.obj") + t.expect_nothing_more() + + # --reconfigure should re-run configuration checks only + t.run_build_system(["--reconfigure"]) + t.expect_output_lines([ + " - pass builds : yes", + " - fail builds : no"]) + t.expect_touch("bin/$toolset/debug*/pass.obj") + t.expect_nothing_more() + + # -a -n should not rebuild configuration checks + t.run_build_system(["-a", "-n"]) + t.expect_output_lines([ + " - pass builds : yes (cached)", + " - fail builds : no (cached)"]) + t.expect_nothing_more() + + # --clean-all should clear all configuration checks + t.run_build_system(["--clean-all"]) + t.expect_output_lines([ + " - pass builds : yes (cached)", + " - fail builds : no (cached)"]) + t.expect_removal("bin/$toolset/debug*/pass.obj") + t.expect_removal("bin/$toolset/debug*/foo.obj") + t.expect_removal("bin/$toolset/debug*/bar.obj") + t.expect_nothing_more() + + # If configuration checks are absent, then --clean-all + # should create them and then delete them again. This + # currently fails because clean cannot remove targets + # that were created in the same build. + #t.run_build_system(["--clean-all"]) + #t.expect_output_lines([ + # " - pass builds : yes", + # " - fail builds : no"]) + #t.expect_nothing_more() + + # Just verify that we're actually in the initial + # state here. + t.run_build_system() + t.expect_output_lines([ + " - pass builds : yes", + " - fail builds : no"]) + t.expect_addition("bin/$toolset/debug*/pass.obj") + t.expect_addition("bin/$toolset/debug*/foo.obj") + t.expect_addition("bin/$toolset/debug*/bar.obj") + t.expect_nothing_more() + + t.cleanup() + +def test_choose(): + t = BoostBuild.Tester(use_test_config=0) + t.write("Jamroot", """ +import configure ; +obj pass : pass.cpp ; +obj fail : fail.cpp ; +explicit pass fail ; +obj foo : foo.cpp : + [ configure.choose "which one?" : fail <define>FAIL : pass <define>PASS ] ; +""") + t.write("pass.cpp", "void f() {}\n") + t.write("fail.cpp", "#error fail.cpp\n") + t.write("foo.cpp", """ +#ifndef PASS +#error PASS not defined +#endif +#ifdef FAIL +#error FAIL is defined +#endif +""") + t.run_build_system() + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_addition("bin/$toolset/debug*/pass.obj") + t.expect_addition("bin/$toolset/debug*/foo.obj") + t.expect_nothing_more() + + # An up-to-date build should use the cache + t.run_build_system() + t.expect_output_lines([ + " - which one? : pass (cached)"]) + t.expect_nothing_more() + + # -a should re-run everything, including configuration checks + t.run_build_system(["-a"]) + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_touch("bin/$toolset/debug*/pass.obj") + t.expect_touch("bin/$toolset/debug*/foo.obj") + t.expect_nothing_more() + + # --reconfigure should re-run configuration checks only + t.run_build_system(["--reconfigure"]) + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_touch("bin/$toolset/debug*/pass.obj") + t.expect_nothing_more() + + # -a -n should not rebuild configuration checks + t.run_build_system(["-a", "-n"]) + t.expect_output_lines([ + " - which one? : pass (cached)"]) + t.expect_nothing_more() + + # --clean-all should clear all configuration checks + t.run_build_system(["--clean-all"]) + t.expect_output_lines([ + " - which one? : pass (cached)"]) + t.expect_removal("bin/$toolset/debug*/pass.obj") + t.expect_removal("bin/$toolset/debug*/foo.obj") + t.expect_nothing_more() + + # If configuration checks are absent, then --clean-all + # should create them and then delete them again. This + # currently fails because clean cannot remove targets + # that were created in the same build. + #t.run_build_system(["--clean-all"]) + #t.expect_output_lines([ + # " - which one? : pass"]) + #t.expect_nothing_more() + + # Just verify that we're actually in the initial + # state here. + t.run_build_system() + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_addition("bin/$toolset/debug*/pass.obj") + t.expect_addition("bin/$toolset/debug*/foo.obj") + t.expect_nothing_more() + + t.cleanup() + +def test_translation(): + """Tests scoping for targets, paths, and rules within check-target-builds""" + t = BoostBuild.Tester(use_test_config=0) + t.write("Jamroot", "") + t.write("subdir/Jamfile", """ +import configure ; +obj pass : pass.cpp ; +obj fail : fail.cpp ; +explicit pass fail ; +obj foo : : + [ configure.check-target-builds pass + : [ configure.check-target-builds fail : <define>FAIL + : <define>PASS <include>include1 <conditional>@c1 ] + : <define>FAIL ] ; +obj bar : : + [ configure.choose "which one?" : pass + [ configure.choose "Try again?" : pass + <define>PASS <include>include1 <conditional>@c1 ] ] ; +rule c1 ( properties * ) +{ + return <include>include2 <source>foo.cpp ; +} +""") + t.write("subdir/include1/a.h", "") + t.write("subdir/include2/b.h", "") + t.write("subdir/pass.cpp", "void f() {}\n") + t.write("subdir/fail.cpp", "#error fail.cpp\n") + t.write("subdir/foo.cpp", """ +#include <a.h> +#include <b.h> +#ifndef PASS +#error PASS not defined +#endif +#ifdef FAIL +#error FAIL is defined +#endif +""") + t.run_build_system(["subdir"]) + t.expect_output_lines([ + " - pass builds : yes", + " - fail builds : no"]) + t.expect_addition("subdir/bin/$toolset/debug*/pass.obj") + t.expect_addition("subdir/bin/$toolset/debug*/foo.obj") + t.expect_addition("subdir/bin/$toolset/debug*/bar.obj") + t.expect_nothing_more() + t.cleanup() + +def test_choose_none(): + """Tests choose when none of the alternatives match.""" + t = BoostBuild.Tester(use_test_config=0) + t.write("Jamroot", """ +import configure ; +obj fail : fail.cpp ; +explicit pass fail ; +obj foo : foo.cpp : + [ configure.choose "which one?" : fail <define>FAIL ] ; +""") + t.write("fail.cpp", "#error fail.cpp\n") + t.write("foo.cpp", """ +#ifdef FAIL +#error FAIL is defined +#endif +""") + t.run_build_system() + t.expect_output_lines([ + " - which one? : none"]) + + # An up-to-date build should use the cache + t.run_build_system() + t.expect_output_lines([ + " - which one? : none (cached)"]) + t.expect_nothing_more() + t.cleanup() + +test_check_target_builds() +test_choose() +test_translation() +test_choose_none() diff --git a/src/boost/tools/build/test/copy_time.py b/src/boost/tools/build/test/copy_time.py new file mode 100755 index 00000000..a036fe62 --- /dev/null +++ b/src/boost/tools/build/test/copy_time.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# +# Copyright (c) 2008 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that the common.copy rule set the modification date of the new file to +# the current time. + +import BoostBuild + +tester = BoostBuild.Tester(use_test_config=False) + +tester.write("test1.cpp", """\ +template<bool, int M, class Next> +struct time_waster { + typedef typename time_waster<true, M-1, time_waster>::type type1; + typedef typename time_waster<false, M-1, time_waster>::type type2; + typedef void type; +}; +template<bool B, class Next> +struct time_waster<B, 0, Next> { + typedef void type; +}; +typedef time_waster<true, 10, void>::type type; +int f() { return 0; } +""") + +tester.write("test2.cpp", """\ +template<bool, int M, class Next> +struct time_waster { + typedef typename time_waster<true, M-1, time_waster>::type type1; + typedef typename time_waster<false, M-1, time_waster>::type type2; + typedef void type; +}; +template<bool B, class Next> +struct time_waster<B, 0, Next> { + typedef void type; +}; +typedef time_waster<true, 10, void>::type type; +int g() { return 0; } +""") + +tester.write("jamroot.jam", """\ +obj test2 : test2.cpp ; +obj test1 : test1.cpp : <dependency>test2 ; +install test2i : test2 : <dependency>test1 ; +""") + +tester.run_build_system() +tester.expect_addition("bin/$toolset/debug*/test2.obj") +tester.expect_addition("bin/$toolset/debug*/test1.obj") +tester.expect_addition("test2i/test2.obj") +tester.expect_nothing_more() + +test2src = tester.read("test2i/test2.obj", binary=True) +test2dest = tester.read("bin/$toolset/debug*/test2.obj", binary=True) +if test2src != test2dest: + BoostBuild.annotation("failure", "The object file was not copied " + "correctly") + tester.fail_test(1) + +tester.run_build_system(["-d1"]) +tester.expect_output_lines("common.copy*", False) +tester.expect_nothing_more() + +tester.cleanup() diff --git a/src/boost/tools/build/test/core-language/test.jam b/src/boost/tools/build/test/core-language/test.jam new file mode 100644 index 00000000..778bd572 --- /dev/null +++ b/src/boost/tools/build/test/core-language/test.jam @@ -0,0 +1,1563 @@ +# Copyright 2011 Steven Watanabe. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tools + +passed = 0 ; +failed = 0 ; + +rule show-result ( id : test-result ) +{ + if ! ( --quiet in $(ARGV) ) + { + ECHO $(test-result): $(id) ; + } + $(test-result) = [ CALC $($(test-result)) + 1 ] ; +} + +rule check-equal ( id : values * : expected * ) +{ + local test-result ; + if x$(values) = x$(expected) + { + test-result = passed ; + } + else + { + ECHO error: "[" $(values) "] != [" $(expected) "]" ; + test-result = failed ; + } + show-result $(id) : $(test-result) ; +} + +rule mark-order ( id : result * ) +{ + order += $(id) ; + return $(result) ; +} + +rule check-order ( id : expected * ) +{ + check-equal $(id) : $(order) : $(expected) ; + order = ; +} + +# Check variable expansion + +{ + +local v1 = 1 2 3 ; +local v2 = 4 5 6 ; +local v3 = 0 1 2 3 4 5 6 7 8 9 10 ; +local g = g1 g2 ; +local v4 = String/With/Mixed/Case ; +local v5 = path\\with\\backslashes ; +local v6 = <grist>generic/path.txt(member.txt) ; +local v7 = <Grist1>Dir1/File1.cpp(M1.c) <Grist2>Dir2/File2.hpp(M2.c) ; +local v8 = <Grist3>Dir3/File3.c(M3.c) <Grist4>Dir4/File4.h(M4.c) ; +local select1 = GU BL DBST ; +local case1 = L U ; +local vars = 7 8 ; +local sub = 2 1 ; +local p0 = name ; +local p1 = dir/name ; +local p2 = dir/sub/name ; +local j1 = , - ; + +check-equal var-product : $(v1)$(v2) : 14 15 16 24 25 26 34 35 36 ; + +check-equal var-set-grist : $(v1:G=grist) : <grist>1 <grist>2 <grist>3 ; +check-equal var-set-grist-multi : $(v1:G=$(g)) : <g1>1 <g1>2 <g1>3 <g2>1 <g2>2 <g2>3 ; + +check-equal var-lower : $(v4:L) : string/with/mixed/case ; +check-equal var-upper : $(v4:U) : STRING/WITH/MIXED/CASE ; +check-equal var-LU : $(v4:LU) : STRING/WITH/MIXED/CASE ; +check-equal var-slashes : $(v5:T) : path/with/backslashes ; +check-equal var-grist : $(v6:G) : <grist> ; +check-equal var-grist-none : $(v1:G) : "" "" "" ; +check-equal var-base : $(v6:B) : path ; +check-equal var-suffix : $(v6:S) : .txt ; +check-equal var-dir : $(v6:D) : generic ; +check-equal var-member : $(v6:M) : (member.txt) ; +check-equal var-multi : $(v6:$(select1)) : <GRIST> path generic/path.txt ; + +check-equal var-join-0 : $(:J=,) : ; +check-equal var-join-1 : $(p0:J=,) : name ; +check-equal var-join-3 : $(v1:J=,) : 1,2,3 ; +check-equal var-set-grist-join : $(v1:G=grist:J=,) : <grist>1,<grist>2,<grist>3 ; +# behavior change. In the past, a J= modifier would +# cause only the last element of the other modifiers +# to take effect. +check-equal var-set-grist-multi-join : $(v1:G=$(g):J=,) : <g1>1,<g1>2,<g1>3 <g2>1,<g2>2,<g2>3 ; +check-equal var-set-grist-multi-join-multi : $(v1:G=$(g):J=$(j1)) : <g1>1,<g1>2,<g1>3 <g1>1-<g1>2-<g1>3 <g2>1,<g2>2,<g2>3 <g2>1-<g2>2-<g2>3 ; + +check-equal var-D=-0 : name : $(p0:D=) ; +check-equal var-D=-1 : name : $(p1:D=) ; +check-equal var-D=-2 : name : $(p2:D=) ; +check-equal var-D-0 : "" : $(p0:D) ; +check-equal var-D-1 : dir : $(p1:D) ; +check-equal var-D-2 : dir/sub : $(p2:D) ; +check-equal var-S-1 : "" : $(p0:S) ; +check-equal var-no-at-file-0 : ($(p0)) : [ MATCH ^@(.*) : "@($(p0))" ] ; +check-equal var-no-at-file-1 : ($(p0)) : [ MATCH @(.*) : "--@($(p0))" ] ; + +if $(OS) = CYGWIN +{ + local cyg-root = $(:WE=/) ; + local cyg1 = /cygdrive/c/path1.txt ; + check-equal cygwin-to-cygdrive : $(cyg1:W) : C:\\path1.txt ; + local cyg2 = /bin/bash ; + check-equal cygwin-to-windows : $(cyg2:W) : $(cyg-root)\\bin\\bash ; + check-equal cygwin-combine-WT : $(cyg2:WT) : $(cyg-root)\\bin\\bash ; + + local cyg3 = /home/boost/devel/trunk/bin.v2/ ; # exactly 31 characters + local win3 = $(cyg-root)\\home\\boost\\devel\\trunk\\bin.v2\\ ; + # This is is the easiest way to demonstrate a bug + # that used to cause undefined behavior. Longer paths + # resulted in a use-after-free error, which happened + # to work most of the time. + check-equal cygwin-long-WU : $(cyg3:WU) : $(win3:U) ; + + local cyg-grist = <grist>$(cyg1) ; + check-equal cygwin-grist : $(cyg-grist:W) : <grist>\\cygdrive\\c\\path1.txt ; + + check-equal cygwin-WU : $(cyg2:WU) : $(cyg-root:U)\\BIN\\BASH ; + # behavior change: L now consistently applied after W. + # used to affect all except the drive letter. + check-equal cygwin-WL : $(cyg2:WL) : $(cyg-root:L)\\bin\\bash ; +} + +# behavior change +check-equal var-test1 : $(v7[2]:G:L) : <grist2> ; + +check-equal var-multi-product-smm : $(v$(vars)[$(sub)]:G=$(g):$(case1)) : + <g1>dir2/file2.hpp(m2.c) <G1>DIR2/FILE2.HPP(M2.C) + <g2>dir2/file2.hpp(m2.c) <G2>DIR2/FILE2.HPP(M2.C) + <g1>dir1/file1.cpp(m1.c) <G1>DIR1/FILE1.CPP(M1.C) + <g2>dir1/file1.cpp(m1.c) <G2>DIR1/FILE1.CPP(M1.C) + <g1>dir4/file4.h(m4.c) <G1>DIR4/FILE4.H(M4.C) + <g2>dir4/file4.h(m4.c) <G2>DIR4/FILE4.H(M4.C) + <g1>dir3/file3.c(m3.c) <G1>DIR3/FILE3.C(M3.C) + <g2>dir3/file3.c(m3.c) <G2>DIR3/FILE3.C(M3.C) +; +check-equal var-nopathmods : $(:E=//) : // ; + +# showcases all the idiosyncracies of indexing +# key: h = high, l = low, p = positive, m = minus, e = end. + +check-equal var-subscript-one-p : $(v3[3]) : 2 ; +check-equal var-subscript-one-m : $(v3[-3]) : 8 ; +check-equal var-subscript-one-0 : $(v3[0]) : 0 ; +check-equal var-subscript-one-h : $(v3[20]) : ; +check-equal var-subscript-one-l : $(v3[-20]) : 0 ; +check-equal var-subscript-range-pp : $(v3[2-4]) : 1 2 3 ; +check-equal var-subscript-range-pm : $(v3[2--3]) : 1 2 3 4 5 6 7 8 ; +check-equal var-subscript-range-pe : $(v3[2-]) : 1 2 3 4 5 6 7 8 9 10 ; +check-equal var-subscript-range-ph : $(v3[2-20]) : 1 2 3 4 5 6 7 8 9 10 ; +check-equal var-subscript-range-pl : $(v3[2--20]) : ; +check-equal var-subscript-range-mp : $(v3[-3-10]) : 8 9 ; +check-equal var-subscript-range-mm : $(v3[-4--2]) : 7 8 9 ; +check-equal var-subscript-range-me : $(v3[-4-]) : 7 8 9 10 ; +check-equal var-subscript-range-mh : $(v3[-4-20]) : 7 8 9 10 ; +check-equal var-subscript-range-mh : $(v3[-4--20]) : ; +check-equal var-subscript-range-0p : $(v3[0-2]) : 0 1 2 ; +check-equal var-subscript-range-0m : $(v3[0--4]) : 0 1 2 3 4 5 6 7 8 ; +check-equal var-subscript-range-0e : $(v3[0-]) : 0 1 2 3 4 5 6 7 8 9 10 ; +check-equal var-subscript-range-0h : $(v3[0-20]) : 0 1 2 3 4 5 6 7 8 9 10 ; +check-equal var-subscript-range-0l : $(v3[0--20]) : ; +check-equal var-subscript-range-hp : $(v3[20-4]) : ; +check-equal var-subscript-range-hm : $(v3[20--4]) : ; +check-equal var-subscript-range-he : $(v3[20-]) : ; +check-equal var-subscript-range-hh : $(v3[20-20]) : ; +check-equal var-subscript-range-hl : $(v3[20--20]) : ; +check-equal var-subscript-range-lp : $(v3[-13-4]) : 0 1 2 3 4 5 ; +check-equal var-subscript-range-lm : $(v3[-13--4]) : 0 1 2 3 4 5 6 7 8 9 ; +check-equal var-subscript-range-le : $(v3[-13-]) : 0 1 2 3 4 5 6 7 8 9 10 ; +check-equal var-subscript-range-lh : $(v3[-13-20]) : 0 1 2 3 4 5 6 7 8 9 10 ; +check-equal var-subscript-range-ll : $(v3[-13--13]) : 0 ; +check-equal var-subscript-range-empty : $(v3[4-3]) : ; + +} + +# Check rules + +{ + +rule test-rule +{ + return $(<) - $(>) - $(1) - $(2) - $(3) - $(4) - $(5) - $(6) - $(7) - $(8) - $(9) - $(10) - $(11) - $(12) - $(13) - $(14) - $(15) - $(16) - $(17) - $(18) - $(19) ; +} + +check-equal rule-arguments-numbered : + [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] : + a1 - a2 - a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ; + +rule test-rule +{ + return $(<:L) - $(>:L) - $(1:L) - $(2:L) - $(3:L) - $(4:L) - $(5:L) - $(6:L) - $(7:L) - $(8:L) - $(9:L) - $(10:L) - $(11:L) - $(12:L) - $(13:L) - $(14:L) - $(15:L) - $(16:L) - $(17:L) - $(18:L) - $(19:L) ; +} + +# behavior change +check-equal rule-arguments-numbered-lower : + [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] : + a1 - a2 - a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ; + + +rule test-rule ( p1 : p2 : p3 : p4 : p5 : p6 : p7 : p8 : p9 : + p10 : p11 : p12 : p13 : p14 : p15 : p16 : p17 : p18 : p19 ) + + +{ + return $(p1) - $(p2) - $(p3) - $(p4) - $(p5) - $(p6) - $(p7) - $(p8) - $(p9) - $(p10) - $(p11) - $(p12) - $(p13) - $(p14) - $(p15) - $(p16) - $(p17) - $(p18) - $(p19) ; +} + +check-equal rule-arguments-named : + [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] : + a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ; + +# +# test rule indirection +# +rule select ( n list * ) +{ + return $(list[$(n)]) ; +} + +rule indirect1 ( rule + : args * ) +{ + return [ $(rule) $(args) ] ; +} + +check-equal rule-indirect-1 : [ indirect1 select 1 : a b c d e ] : a ; +check-equal rule-indirect-2 : [ indirect1 select 2 : a b c d e ] : b ; + +x = reset ; +rule reset-x ( new-value ) +{ + x = $(new-value) ; +} +$(x)-x bar ; # invokes reset-x... +check-equal rule-reset : $(x) : bar ; # which changes x + +rule bar-x ( new-value ) +{ + mark-order r3 ; +} + +# The arguments are evaluated in forward order +# before the rule name +$(x)-x [ mark-order r1 : [ reset-x reset ] ] : [ mark-order r2 ] ; +check-order rule-order : r1 r2 ; + +# Cases that look like member calls +rule looks.like-a-member ( args * ) +{ + return $(args) ; +} + +rule call-non-member ( rule + ) +{ + return [ $(rule).like-a-member ] ; +} + +rule call-non-member-with-args ( rule + ) +{ + return [ $(rule).like-a-member a2 ] ; +} + +check-equal rule-non-member : [ call-non-member looks ] : ; +#check-equal rule-non-member-a1 : [ call-non-member looks a1 ] : looks.a1 ; +check-equal rule-non-member-args : [ call-non-member-with-args looks ] : a2 ; +#check-equal rule-non-member-args-a1 : [ call-non-member-with-args looks a1 ] : looks.a1 a2 ; + +} + +# Check append + +{ + +local value = [ mark-order r1 : v1 v2 ] [ mark-order r2 : v3 v4 ] ; +check-equal append : $(value) : v1 v2 v3 v4 ; +check-order append-order : r1 r2 ; + +} + +# Check foreach + +{ + +local v1 = 1 2 3 ; +local x = old ; +local result ; + +for local x in $(v1) +{ + result += $(x) + ; +} + +check-equal foreach-local-item : $(result) : 1 + 2 + 3 + ; +check-equal foreach-local : $(x) : old ; + +result = ; + +for x in $(v1) +{ + result += $(x) + ; +} + +check-equal foreach-nonlocal-item : $(result) : 1 + 2 + 3 + ; +check-equal foreach-nonlocal : $(x) : 3 ; + +rule call-foreach ( values * ) +{ + for local x in $(values) + { + return $(x) ; + } +} + +check-equal foreach-result : [ call-foreach 1 2 3 ] : 1 ; + +result = ; +local varname = x ; +x = old ; + +for local $(varname) in $(v1) +{ + result += $(x) + ; +} + +check-equal foreach-no-expand : $(result) : old + old + old + ; + +result = ; + +for local v1 in $(v1) +{ + result += $(v1) + ; +} + +check-equal foreach-order : $(result) : 1 + 2 + 3 + ; + +} + +# Check if + +{ + +if true +{ + mark-order r1 ; +} + +check-order if-true : r1 ; + +if $(false) +{ + mark-order r1 ; +} + +check-order if-false : ; + +if true +{ + mark-order r1 ; +} +else +{ + mark-order r2 ; +} + +check-order if-else-true : r1 ; + +if $(false) +{ + mark-order r1 ; +} +else +{ + mark-order r2 ; +} + +check-order if-else-false : r2 ; + +rule test-rule +{ + if true + { + return result ; + } +} + +check-equal if-true-result : [ test-rule ] : result ; + +rule test-rule +{ + local idx = 1 2 ; + local values = true ; + while $(idx) + { + local v = $(values[$(idx[1])]) ; + idx = $(idx[2-]) ; + if $(v) + { + return result ; + } + } +} + +check-equal if-false-result : [ test-rule ] : result ; + +rule test-rule +{ + if true + { + return r1 ; + } + else + { + return r2 ; + } +} + +check-equal if-else-true-result : [ test-rule ] : r1 ; + +rule test-rule +{ + if $(false) + { + return r1 ; + } + else + { + return r2 ; + } +} + +check-equal if-else-false-result : [ test-rule ] : r2 ; + +} + +# Check the evaluation of conditions + +{ + +local test-result ; +local v1 = "" "" "" ; +local v2 = ; +local v3 = a b c ; +local v4 = a b c d ; +local v5 = a b d ; +local v6 = "" "" "" d ; + +rule test-comparison ( id : equal less greater ) +{ + check-equal $(id)-empty-1 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ; + check-equal $(id)-empty-2 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ; + check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(equal) ; + check-equal $(id)-less-1 : [ eval-$(id) $(v3) : $(v4) ] : $(less) ; + check-equal $(id)-less-2 : [ eval-$(id) $(v3) : $(v5) ] : $(less) ; + check-equal $(id)-less-3 : [ eval-$(id) $(v4) : $(v5) ] : $(less) ; + check-equal $(id)-greater-1 : [ eval-$(id) $(v4) : $(v3) ] : $(greater) ; + check-equal $(id)-greater-2 : [ eval-$(id) $(v5) : $(v3) ] : $(greater) ; + check-equal $(id)-greater-3 : [ eval-$(id) $(v5) : $(v4) ] : $(greater) ; +} + +rule eval-lt ( lhs * : rhs * ) +{ + if $(lhs) < $(rhs) { return true ; } + else { return false ; } +} + +test-comparison lt : false true false ; + +rule eval-gt ( lhs * : rhs * ) +{ + if $(lhs) > $(rhs) { return true ; } + else { return false ; } +} + +test-comparison gt : false false true ; + +rule eval-le ( lhs * : rhs * ) +{ + if $(lhs) <= $(rhs) { return true ; } + else { return false ; } +} + +test-comparison le : true true false ; + +rule eval-ge ( lhs * : rhs * ) +{ + if $(lhs) >= $(rhs) { return true ; } + else { return false ; } +} + +test-comparison ge : true false true ; + +rule eval-eq ( lhs * : rhs * ) +{ + if $(lhs) = $(rhs) { return true ; } + else { return false ; } +} + +test-comparison eq : true false false ; + +rule eval-ne ( lhs * : rhs * ) +{ + if $(lhs) != $(rhs) { return true ; } + else { return false ; } +} + +test-comparison ne : false true true ; + +rule eval-not-lt ( lhs * : rhs * ) +{ + if ! ( $(lhs) < $(rhs) ) { return true ; } + else { return false ; } +} + +test-comparison not-lt : true false true ; + +rule eval-not-gt ( lhs * : rhs * ) +{ + if ! ( $(lhs) > $(rhs) ) { return true ; } + else { return false ; } +} + +test-comparison not-gt : true true false ; + +rule eval-not-le ( lhs * : rhs * ) +{ + if ! ( $(lhs) <= $(rhs) ) { return true ; } + else { return false ; } +} + +test-comparison not-le : false false true ; + +rule eval-not-ge ( lhs * : rhs * ) +{ + if ! ( $(lhs) >= $(rhs) ) { return true ; } + else { return false ; } +} + +test-comparison not-ge : false true false ; + +rule eval-not-eq ( lhs * : rhs * ) +{ + if ! ( $(lhs) = $(rhs) ) { return true ; } + else { return false ; } +} + +test-comparison not-eq : false true true ; + +rule eval-not-ne ( lhs * : rhs * ) +{ + if ! ( $(lhs) != $(rhs) ) { return true ; } + else { return false ; } +} + +test-comparison not-ne : true false false ; + +local v7 = a a a a a a ; +local v8 = c b ; +local v9 = c d b ; +local v10 = c a b c c b a a a ; + +rule test-in ( id : subset not-subset ) +{ + check-equal $(id)-0-0 : [ eval-$(id) $(v2) : $(v2) ] : $(subset) ; + check-equal $(id)-0-empty : [ eval-$(id) $(v2) : $(v1) ] : $(subset) ; + check-equal $(id)-empty-0 : [ eval-$(id) $(v1) : $(v2) ] : $(not-subset) ; + check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(subset) ; + check-equal $(id)-simple : [ eval-$(id) $(v3) : $(v4) ] : $(subset) ; + check-equal $(id)-extra : [ eval-$(id) $(v4) : $(v3) ] : $(not-subset) ; + check-equal $(id)-multiple : [ eval-$(id) $(v7) : $(v3) ] : $(subset) ; + check-equal $(id)-unordered : [ eval-$(id) $(v8) : $(v3) ] : $(subset) ; + check-equal $(id)-unordered-extra : [ eval-$(id) $(v9) : $(v3) ] : $(not-subset) ; + check-equal $(id)-unordered-multiple : [ eval-$(id) $(v10) : $(v3) ] : $(subset) ; +} + +rule eval-in ( lhs * : rhs * ) +{ + if $(lhs) in $(rhs) { return true ; } + else { return false ; } +} + +test-in "in" : true false ; + +rule eval-not-in ( lhs * : rhs * ) +{ + if ! ( $(lhs) in $(rhs) ) { return true ; } + else { return false ; } +} + +test-in not-in : false true ; + +rule test-truth-table ( id : tt tf ft ff ) +{ + check-equal $(id)-tt : [ eval-$(id) 1 : 1 ] : $(tt) ; + check-equal $(id)-tf : [ eval-$(id) 1 : ] : $(tf) ; + check-equal $(id)-ft : [ eval-$(id) : 1 ] : $(ft) ; + check-equal $(id)-ff : [ eval-$(id) : ] : $(ff) ; +} + +rule eval-and ( lhs ? : rhs ? ) +{ + if $(lhs) && $(rhs) { return true ; } + else { return false ; } +} + +test-truth-table and : true false false false ; + +rule eval-or ( lhs ? : rhs ? ) +{ + if $(lhs) || $(rhs) { return true ; } + else { return false ; } +} + +test-truth-table or : true true true false ; + +rule eval-not-and ( lhs ? : rhs ? ) +{ + if ! ( $(lhs) && $(rhs) ) { return true ; } + else { return false ; } +} + +test-truth-table not-and : false true true true ; + +rule eval-not-or ( lhs ? : rhs ? ) +{ + if ! ( $(lhs) || $(rhs) ) { return true ; } + else { return false ; } +} + +test-truth-table not-or : false false false true ; + +if [ mark-order r1 : test1 ] < [ mark-order r2 : test2 ] { } +check-order lt-order : r1 r2 ; +if [ mark-order r1 : test1 ] > [ mark-order r2 : test2 ] { } +check-order gt-order : r1 r2 ; +if [ mark-order r1 : test1 ] <= [ mark-order r2 : test2 ] { } +check-order le-order : r1 r2 ; +if [ mark-order r1 : test1 ] >= [ mark-order r2 : test2 ] { } +check-order ge-order : r1 r2 ; +if [ mark-order r1 : test1 ] = [ mark-order r2 : test2 ] { } +check-order eq-order : r1 r2 ; +if [ mark-order r1 : test1 ] != [ mark-order r2 : test2 ] { } +check-order ne-order : r1 r2 ; +if [ mark-order r1 : test1 ] in [ mark-order r2 : test2 ] { } +check-order in-order : r1 r2 ; + +if [ mark-order r1 : test1 ] && [ mark-order r2 : test2 ] { } +check-order and-order : r1 r2 ; +if [ mark-order r1 ] && [ mark-order r2 : test2 ] { } +check-order and-order-short-circuit : r1 ; + +if [ mark-order r1 ] || [ mark-order r2 : test2 ] { } +check-order or-order : r1 r2 ; +if [ mark-order r1 : test1 ] || [ mark-order r2 : test2 ] { } +check-order or-order-short-circuit : r1 ; + +} + +# Check include + +{ +#FIXME: +# plain include +# include in module +# include returns an empty list +# rule arguments are available inside include +} + +# Check local + +{ + +local v1 = a b c ; +local v2 = f g h ; + +{ + local v1 ; + check-equal local-no-init : $(v1) : ; +} + +check-equal local-restore : $(v1) : a b c ; + +{ + local v1 = d e f ; + check-equal local-init : $(v1) : d e f ; +} + +check-equal local-restore-init : $(v1) : a b c ; + +{ + local v1 v2 ; + check-equal local-multiple-no-init : $(v1) - $(v2) : - ; +} + +check-equal local-multiple-restore : $(v1) - $(v2) : a b c - f g h ; + +{ + local v1 v2 = d e f ; + check-equal local-multiple-init : $(v1) - $(v2) : d e f - d e f ; +} + +{ + local v1 v1 = d e f ; + check-equal local-duplicate : $(v1) - $(v1) : d e f - d e f ; +} + +check-equal local-duplicate-restore : $(v1) : a b c ; + +{ + local [ mark-order r1 : v1 ] = [ mark-order r2 : d e f ] ; + check-order local-order : r1 r2 ; +} + +} + +# Check module + +{ + local var1 = root-module-var ; + module my_module + { + var1 = module-var ; + rule get ( ) + { + return $(var1) ; + } + local rule not_really ( ) { return nothing ; } + } + + check-equal module-var-not-root : $(var1) : root-module-var ; + + check-equal module-rulenames : [ RULENAMES my_module ] : get ; + + IMPORT_MODULE my_module ; + check-equal module-rule-import-module : [ my_module.get ] : module-var ; + + IMPORT my_module : get : : module-get ; + check-equal module-rule-imort : [ module-get ] : module-var ; + + IMPORT my_module : get : : module-get : LOCALIZE ; + check-equal module-rule-imort-localize : [ module-get ] : root-module-var ; + +} + +# Check class +{ +#FIXME: +# ... +} + +# Check on + +{ + +local target1 = test-on-target1 ; +local target2 = test-on-target2 ; +local targets = $(target1) $(target2) ; +local v1 v2 v3 ; + +VAR on $(target1) = value1 ; +V2 on $(target2) = value2 ; + +check-equal on-return : [ on $(target1) return $(VAR) ] : value1 ; + +rule test-rule +{ + return $(VAR) ; +} + +check-equal on-rule : [ on $(target1) test-rule ] : value1 ; + +check-equal on-multiple : [ on $(targets) return $(V2) ] : ; + +rule test-rule +{ + on $(target1) + { + return $(VAR) ; + } +} + +check-equal on-block : [ test-rule ] : value1 ; + +# FIXME: crazy implementation artifacts: + +v1 on test-on-target3 = x1 ; +on test-on-target3 +{ + v1 on test-on-target3 += x1 ; + v1 = y1 ; + v2 on test-on-target3 += x2 ; + v2 = y2 ; + v3 = y3 ; +} + +check-equal on-swap-old1 : $(v1) : x1 ; +check-equal on-swap-old2 : [ on test-on-target3 return $(v1) ] : y1 ; +check-equal on-swap-new1 : $(v2) : x2 ; +check-equal on-swap-new2 : [ on test-on-target3 return $(v2) ] : y2 ; +check-equal on-no-swap : $(v3) : y3 ; + +} + +# Check rule + +{ +#FIXME: +# argument order +# expand rule name +} + +# Check rules + +{ +#FIXME: +} + +# Check set + +{ +local v1 ; +local v2 ; +local v3 ; +local vars = v1 v2 v3 ; + +v1 = x1 ; +check-equal set-set-empty : $(v1) : x1 ; +v2 += x2 ; +check-equal set-append-empty : $(v2) : x2 ; +v3 ?= x3 ; +check-equal set-default-empty : $(v3) : x3 ; + +v1 = y1 ; +check-equal set-set-non-empty : $(v1) : y1 ; +v2 += y2 ; +check-equal set-append-non-empty : $(v2) : x2 y2 ; +v3 ?= y3 ; +check-equal set-default-non-empty : $(v3) : x3 ; + +v1 = ; +v2 = ; +v3 = ; +$(vars) = z ; +check-equal set-set-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ; + +v1 = ; +v2 = ; +v3 = ; +$(vars) += z ; +check-equal set-append-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ; + +v1 = ; +v2 = ; +v3 = ; +$(vars) ?= z ; +check-equal set-default-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ; + +v1 = x1 ; +v2 = x2 ; +v3 = x3 ; +$(vars) = z ; +check-equal set-set-non-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ; + +v1 = x1 ; +v2 = x2 ; +v3 = x3 ; +$(vars) += z ; +check-equal set-append-non-empty-group : $(v1) - $(v2) - $(v3) : x1 z - x2 z - x3 z ; + +v1 = x1 ; +v2 = x2 ; +v3 = x3 ; +$(vars) ?= z ; +check-equal set-default-non-empty-group : $(v1) - $(v2) - $(v3) : x1 - x2 - x3 ; + +v1 = x1 ; +v2 = ; +v3 = x3 ; +$(vars) = z ; +check-equal set-set-mixed-group : $(v1) - $(v2) - $(v3) : z - z - z ; + +v1 = x1 ; +v2 = ; +v3 = x3 ; +$(vars) += z ; +check-equal set-append-mixed-group : $(v1) - $(v2) - $(v3) : x1 z - z - x3 z ; + +v1 = x1 ; +v2 = ; +v3 = x3 ; +$(vars) ?= z ; +check-equal set-default-mixed-group : $(v1) - $(v2) - $(v3) : x1 - z - x3 ; + +vars = v1 v1 ; + +v1 = ; +$(vars) = z ; +check-equal set-set-duplicate-empty : $(v1) : z ; +v1 = ; +$(vars) += z ; +check-equal set-append-duplicate-empty : $(v1) : z z ; +v1 = ; +$(vars) ?= z ; +check-equal set-default-duplicate-empty : $(v1) : z ; + +v1 = x1 ; +$(vars) = z ; +check-equal set-set-duplicate-non-empty : $(v1) : z ; +v1 = x1 ; +$(vars) += z ; +check-equal set-append-duplicate-non-empty : $(v1) : x1 z z ; +v1 = x1 ; +$(vars) ?= z ; +check-equal set-default-duplicate-non-empty : $(v1) : x1 ; + +rule test-rule { v1 = x1 ; } +check-equal set-set-result : [ test-rule ] : x1 ; +rule test-rule { v1 += x1 ; } +check-equal set-append-result : [ test-rule ] : x1 ; +rule test-rule { v1 ?= x1 ; } +check-equal set-default-result : [ test-rule ] : x1 ; + +[ mark-order r1 ] = [ mark-order r2 ] ; +check-order set-set-order : r1 r2 ; +[ mark-order r1 ] += [ mark-order r2 ] ; +check-order set-append-order : r1 r2 ; +[ mark-order r1 ] ?= [ mark-order r2 ] ; +check-order set-default-order : r1 r2 ; + +} + +# Check setcomp + +{ +#FIXME +# Expand arguments +# Don't expand name +} + +# Check setexec + +{ +#FIXME: +# Don't expand name +# Evaluate bindlist +} + +# Check settings ; + +{ + +local target1 = test-settings-target1 ; +local target2 = test-settings-target2 ; +local target3 = test-settings-target3 ; +local targets = $(target2) $(target3) ; + +local vars = v1 v2 v3 ; + +v1 on $(target1) = x1 ; +check-equal settings-set-empty : [ on $(target1) return $(v1) ] : x1 ; +v2 on $(target1) += x2 ; +check-equal settings-append-empty : [ on $(target1) return $(v2) ] : x2 ; +v3 on $(target1) ?= x3 ; +check-equal settings-default-empty : [ on $(target1) return $(v3) ] : x3 ; + +v1 on $(target1) = y1 ; +check-equal settings-set-non-empty : [ on $(target1) return $(v1) ] : y1 ; +v2 on $(target1) += y2 ; +check-equal settings-append-non-empty : [ on $(target1) return $(v2) ] : x2 y2 ; +v3 on $(target1) ?= y3 ; +check-equal settings-default-non-empty : [ on $(target1) return $(v3) ] : x3 ; + +$(vars) on setting-target2 = z ; +check-equal settings-set-empty-group : [ on setting-target2 return $(v1) ] - [ on setting-target2 return $(v2) ] - [ on setting-target2 return $(v3) ] : z - z - z ; + +$(vars) on setting-target3 += z ; +check-equal settings-append-empty-group : [ on setting-target3 return $(v1) ] - [ on setting-target3 return $(v2) ] - [ on setting-target3 return $(v3) ] : z - z - z ; + +$(vars) on setting-target4 ?= z ; +check-equal settings-default-empty-group : [ on setting-target4 return $(v1) ] - [ on setting-target4 return $(v2) ] - [ on setting-target4 return $(v3) ] : z - z - z ; + +v1 on $(target1) = x1 ; +v2 on $(target1) = x2 ; +v3 on $(target1) = x3 ; +$(vars) on $(target1) = z ; +check-equal settings-set-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : z - z - z ; + +v1 on $(target1) = x1 ; +v2 on $(target1) = x2 ; +v3 on $(target1) = x3 ; +$(vars) on $(target1) += z ; +check-equal settings-append-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 z - x2 z - x3 z ; + +v1 on $(target1) = x1 ; +v2 on $(target1) = x2 ; +v3 on $(target1) = x3 ; +$(vars) on $(target1) ?= z ; +check-equal settings-default-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 - x2 - x3 ; + +v1 on setting-target5 = x1 ; +v3 on setting-target5 = x3 ; +$(vars) on setting-target5 = z ; +check-equal settings-set-mixed-group : [ on setting-target5 return $(v1) ] - [ on setting-target5 return $(v2) ] - [ on setting-target5 return $(v3) ] : z - z - z ; + +v1 on setting-target6 = x1 ; +v3 on setting-target6 = x3 ; +$(vars) on setting-target6 += z ; +check-equal settings-append-mixed-group : [ on setting-target6 return $(v1) ] - [ on setting-target6 return $(v2) ] - [ on setting-target6 return $(v3) ] : x1 z - z - x3 z ; + +v1 on setting-target7 = x1 ; +v3 on setting-target7 = x3 ; +$(vars) on setting-target7 ?= z ; +check-equal settings-default-mixed-group : [ on setting-target7 return $(v1) ] - [ on setting-target7 return $(v2) ] - [ on setting-target7 return $(v3) ] : x1 - z - x3 ; + +vars = v1 v1 ; + +$(vars) on setting-target8 = z ; +check-equal settings-set-duplicate-empty : [ on setting-target8 return $(v1) ] : z ; +$(vars) on setting-target9 += z ; +check-equal settings-append-duplicate-empty : [ on setting-target9 return $(v1) ] : z z ; +$(vars) on setting-target10 ?= z ; +check-equal settings-default-duplicate-empty : [ on setting-target10 return $(v1) ] : z ; + +v1 on $(target1) = x1 ; +$(vars) on $(target1) = z ; +check-equal settings-set-duplicate-non-empty : [ on $(target1) return $(v1) ] : z ; +v1 on $(target1) = x1 ; +$(vars) on $(target1) += z ; +check-equal settings-append-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 z z ; +v1 on $(target1) = x1 ; +$(vars) on $(target1) ?= z ; +check-equal settings-default-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 ; + +v1 on $(target1) = ; +v1 on $(target1) ?= z ; +check-equal settings-default-set-but-empty : [ on $(target1) return $(v1) ] : ; + +v1 on $(targets) = multi ; +check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi - multi ; +v2 on $(targets) += multi ; +check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi - multi ; +v3 on $(targets) ?= multi ; +check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ; + +v1 on $(targets) = multi2 ; +check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi2 - multi2 ; +v2 on $(targets) += multi2 ; +check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi multi2 - multi multi2 ; +v3 on $(targets) ?= multi2 ; +check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ; + +rule test-rule { v1 on $(target1) = x1 ; } +check-equal settings-set-result : [ test-rule ] : x1 ; +rule test-rule { v1 on $(target1) += x1 ; } +check-equal settings-append-result : [ test-rule ] : x1 ; +rule test-rule { v1 on $(target1) ?= x1 ; } +check-equal settings-default-result : [ test-rule ] : x1 ; + +[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] = [ mark-order r2 : value ] ; +check-order settings-set-order : r1 r2 r3 ; +[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] += [ mark-order r2 : value ] ; +check-order settings-append-order : r1 r2 r3 ; +[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] ?= [ mark-order r2 : value ] ; +check-order settings-default-order : r1 r2 r3 ; + +} + +# Check switch + +{ + +local pattern = * ; + +switch value +{ + case * : mark-order r1 ; +} + +check-order switch-match-any : r1 ; + +switch value +{ + case v2 : mark-order r1 ; +} + +check-order switch-no-match : ; + +switch value +{ + case $(pattern) : mark-order r1 ; +} + +check-order switch-no-expand : ; + +switch value +{ + case value : mark-order r1 ; + case * : mark-order r2 ; +} + +check-order switch-match-several : r1 ; + +rule test-rule ( value ) +{ + switch $(value) + { + case value : return 1 ; + } +} + +check-equal switch-result-match : [ test-rule value ] : 1 ; +check-equal switch-result-match : [ test-rule v1 ] : ; + +switch $() +{ + case "" : mark-order r1 ; + case * : mark-order r2 ; +} + +check-order switch-empty : r1 ; + +local values = v1 v2 v3 ; +switch $(values) +{ + case v1 : mark-order r1 ; + case v2 : mark-order r2 ; + case v3 : mark-order r3 ; +} + +check-order switch-multiple : r1 ; + +# Test glob matching + +switch value { case * : mark-order r1 ; } +check-order switch-glob-star : r1 ; + +switch value { case va*e : mark-order r1 ; } +check-order switch-glob-star-1 : r1 ; + +switch value { case *a* : mark-order r1 ; } +check-order switch-glob-star-2 : r1 ; + +switch value { case *a*ue* : mark-order r1 ; } +check-order switch-glob-star-3 : r1 ; + +switch value { case *[eaiou]*ue : mark-order r1 ; } +check-order switch-glob-group : r1 ; + +switch value { case *[eaiou]ue : mark-order r1 ; } +check-order switch-glob-group-fail : ; + +switch value { case ?a?ue : mark-order r1 ; } +check-order switch-glob-any : r1 ; + +switch value { case ?lue : mark-order r1 ; } +check-order switch-glob-any-fail : ; + +} + +# Test while + +{ + +local value = 1 2 3 ; + +while $(value) +{ + mark-order r$(value[1]) ; + value = $(value[2-]) ; +} + +check-order while-exec : r1 r2 r3 ; + +rule test-rule +{ + local value = 1 2 3 ; + while $(value) + { + value = $(value[2-]) ; + return x ; + } +} + +check-equal while-result : [ test-rule ] : x ; + +rule test-rule +{ + local value = 1 2 ; + while $(value) + { + value = $(value[2-]) ; + local inner = $(value) ; + while $(inner) + { + inner = $(inner[2-]) ; + return x ; + } + } +} + +check-equal while-result-2 : [ test-rule ] : x ; + +} + + +# +# test break +# + +{ + +local z = original ; +local done ; +while ! $(done) +{ + local z = inner ; + mark-order r1 ; + break ; + mark-order r2 ; + done = true ; +} + +check-order break-while-exec : r1 ; +check-equal break-while-cleanup : $(z) : original ; + +local values = v1 v2 ; + +for y in $(values) +{ + local z = inner ; + mark-order r1-$(y) ; + break ; + mark-order r2-$(y) ; +} + +check-order break-for-exec : r1-v1 ; +check-equal break-for-cleanup : $(z) : original ; + +for local y in $(values) +{ + local z = inner ; + mark-order r1-$(y) ; + break ; + mark-order r2-$(y) ; +} + +check-order break-for-local-exec : r1-v1 ; +check-equal break-for-local-cleanup : $(z) : original ; + +local z1 = z1val ; +local z2 = z2val ; +done = ; +while ! $(done) +{ + local z1 = z1new ; + mark-order r1 ; + for local y in $(values) + { + local z2 = z2new ; + mark-order r2 ; + break ; + mark-order r3 ; + } + mark-order r4 ; + break ; + mark-order r5 ; + done = true ; +} + +check-order break-nested-exec : r1 r2 r4 ; +check-equal break-nested-cleanup1 : $(z1) : z1val ; +check-equal break-nested-cleanup2 : $(z2) : z2val ; + +} + +# +# test continue +# + +{ + +local z = original ; +local done ; +while ! [ mark-order r1 : $(done) ] +{ + local z = inner ; + done = true ; + mark-order r2 ; + continue ; + mark-order r3 ; +} + +check-order continue-while-exec : r1 r2 r1 ; +check-equal continue-while-cleanup : $(z) : original ; + +local values = v1 v2 ; +for y in $(values) +{ + local z = inner ; + mark-order r1-$(y) ; + continue ; + mark-order r2-$(y) ; +} + +check-order continue-for-exec : r1-v1 r1-v2 ; +check-equal continue-for-cleanup : $(z) : original ; + +for local y in $(values) +{ + local z = inner ; + mark-order r1-$(y) ; + continue ; + mark-order r2-$(y) ; +} + +check-order continue-for-local-exec : r1-v1 r1-v2 ; +check-equal continue-for-local-cleanup : $(z) : original ; + +local z1 = z1val ; +local z2 = z2val ; +done = ; +while ! [ mark-order r1 : $(done) ] +{ + local z1 = z1new ; + done = true ; + mark-order r2 ; + for local y in $(values) + { + local z2 = z2new ; + mark-order r3-$(y) ; + continue ; + mark-order r4-$(y) ; + } + mark-order r5 ; + continue ; + mark-order r6 ; +} + +check-order continue-nested-exec : r1 r2 r3-v1 r3-v2 r5 r1 ; +check-equal continue-nested-cleanup1 : $(z1) : z1val ; +check-equal continue-nested-cleanup2 : $(z2) : z2val ; + +} + +# +# test CALLER_MODULE and backtrace +# + +{ + local base = [ BACKTRACE ] ; + base = $(base[2]) ; + rule backtrace ( ) + { + local bt = [ BACKTRACE ] ; + check-equal backtrace-1-file : $(bt) : + test.jam [ CALC $(base) + 4 ] "" backtrace + test.jam [ CALC $(base) + 28 ] module2. module2.f + test.jam [ CALC $(base) + 19 ] module1. module1.f + test.jam [ CALC $(base) + 32 ] "" "module scope" + ; + } + module module1 + { + IMPORT_MODULE module2 : module1 ; + rule f ( ) + { + local m = [ CALLER_MODULE ] ; + check-equal caller-module-root : $(m) ; + module2.f ; + } + } + module module2 + { + rule f ( ) + { + local m = [ CALLER_MODULE ] ; + check-equal caller-module : module1 : $(m) ; + backtrace ; + } + } + IMPORT_MODULE module1 ; + module1.f ; +} + + +# Test NORMALIZE_PATH + +{ +check-equal normalize-path : "." : [ NORMALIZE_PATH ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "" ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "." ] ; +check-equal normalize-path : ".." : [ NORMALIZE_PATH ".." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "/" ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\" ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "//" ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\" ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "//\\\\//\\\\" ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "/." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "/./" ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\///.///\\\\\\" ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "./././././." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "/./././././." ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo" ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/" ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\" ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////" ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////././." ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////./././" ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/.." ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "foo////.." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "///foo/\\\\/.." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\\\foo\\//\\.." ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/./.." ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/././././.." ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/./././bar/./././.././././baz/./././.." ] ; +check-equal normalize-path : "/foo" : [ NORMALIZE_PATH "/foo/./././bar/./././.././././baz/./././.." ] ; +check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/./././bar/./././////.././././baz/./././.." ] ; +check-equal normalize-path : "/foo" : [ NORMALIZE_PATH "/foo/./././bar/./././////.././././baz/./././.." ] ; +check-equal normalize-path : ".." : [ NORMALIZE_PATH "./.." ] ; +check-equal normalize-path : ".." : [ NORMALIZE_PATH "././././.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "../.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "./../.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "././././../.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "./.././././.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "././././.././././.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "..//\\\\\\//.." ] ; +check-equal normalize-path : "../.." : [ NORMALIZE_PATH "../..\\\\/\\\\" ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/../bar/../baz/.." ] ; +check-equal normalize-path : "." : [ NORMALIZE_PATH "foo////..////bar////.//////.////../baz/.." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "/foo/../bar/../baz/.." ] ; +check-equal normalize-path : "/" : [ NORMALIZE_PATH "/foo////..////bar////.//////.////../baz/.." ] ; + +# Invalid rooted paths with leading dotdots. +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../" ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "//\\\\//\\\\/.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "\\\\//\\\\//\\.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../../.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/foo/bar/../baz/../../.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../for/././../././bar/././../././.." ] ; +check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../foo/bar" ] ; + +} + +# Test W32_GETREGNAMES + +{ + +if $(NT) +{ + local sound = "Beep" "ExtendedSounds" ; + local r1 = [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : + values ] ; + check-equal w32_getregnames : $(sound:L) : [ SORT $(r1:L) ] ; + local r2 = [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ; + check-equal w32_getregnames : $(sound:L) : [ SORT $(r2:L) ] ; + + # Some Windows platforms may have additional keys under + # 'CurrentControlSet' which we then remove here so they would not be + # reported as errors by our test. + local rule remove-policies ( param * ) + { + local found ; + local r ; + for local x in $(param:L) + { + if ! x in $(found) && + $(x) in "addservices" "policies" "deleted device ids" "software" + { + found += $(x) ; + } + else + { + r += $(x) ; + } + } + return $(r) ; + } + local CurrentControlSet = "Control" "Enum" "Hardware Profiles" "Services" ; + local r3 = [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" + : subkeys ] ; + check-equal w32_getregnames : $(CurrentControlSet:L) : [ remove-policies + $(r3:L) ] ; + local r4 = [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ; + check-equal w32_getregnames : $(CurrentControlSet:L) : [ remove-policies + $(r4:L) ] ; +} + +} + +# Test SHELL + +{ + +local c = "echo value" ; +if $(OS) = VMS { c = "PIPE WRITE SYS$OUTPUT \"value\"" ; } + +check-equal shell : "value\n" : [ SHELL $(c) ] ; +check-equal shell : "" : [ SHELL $(c) : no-output ] ; +check-equal shell : "value\n" 0 : [ SHELL $(c) : exit-status ] ; +check-equal shell : "" 0 : [ SHELL $(c) : no-output : exit-status ] ; +check-equal shell : "" 0 : [ SHELL $(c) : no-output : exit-status : strip-eol ] ; +check-equal command : "value\n" : [ COMMAND $(c) ] ; +check-equal command : "" : [ COMMAND $(c) : no-output ] ; +check-equal command : "value\n" 0 : [ COMMAND $(c) : exit-status ] ; +check-equal command : "" 0 : [ COMMAND $(c) : no-output : exit-status ] ; + +# buffered output + +local expected = "When the shell output buffer splits on whitespace, the whitespace shouldn't be trimmed. end." ; +local buffered = "echo \"$(expected)\"" ; +if $(OS) = VMS { buffered = "PIPE WRITE SYS$OUTPUT \"$(expected)\"" ; } +if $(OS) = NT { buffered = "echo $(expected)" ; } + +check-equal shell : "$(expected)\n" : [ SHELL $(buffered) ] ; +check-equal shell : "" : [ SHELL $(buffered) : no-output ] ; +check-equal shell : "$(expected)\n" 0 : [ SHELL $(buffered) : exit-status ] ; +check-equal shell : "$(expected)" 0 : [ SHELL $(buffered) : strip-eol : exit-status ] ; +check-equal shell : "" 0 : [ SHELL $(buffered) : no-output : exit-status ] ; +check-equal shell : "" 0 : [ SHELL $(buffered) : no-output : exit-status : strip-eol ] ; +check-equal shell : "$(expected)" 0 : [ SHELL $(buffered) : strip-eol : exit-status ] ; + +check-equal command : "$(expected)\n" : [ COMMAND $(buffered) ] ; +check-equal command : "" : [ COMMAND $(buffered) : no-output ] ; +check-equal command : "$(expected)\n" 0 : [ COMMAND $(buffered) : exit-status ] ; +check-equal command : "$(expected)" 0 : [ COMMAND $(buffered) : strip-eol : exit-status ] ; +check-equal command : "" 0 : [ COMMAND $(buffered) : no-output : exit-status ] ; + +} + +# Test SUBST + +{ + +# Check that unmatched subst returns an empty list +check-equal subst-nomatch : [ SUBST "abc" "d+" x ] : ; + +# Check that a matched subst works +check-equal subst-match : [ SUBST "ddd" "d+" x ] : x ; + +# Check that we can get multiple substitutions from a single invocation +check-equal subst-multiple : [ SUBST "x/y/z" "([^/]*)/([^/]*).*" "\\1" $2 "\\1-\\2" ] : x y x-y ; + +} + +# Test summary + +if $(failed) = 0 +{ + status = 0 ; +} +else +{ + status = 1 ; +} + +EXIT $(passed) passed $(failed) failed : $(status) ; diff --git a/src/boost/tools/build/test/core_action_output.py b/src/boost/tools/build/test/core_action_output.py new file mode 100755 index 00000000..75751986 --- /dev/null +++ b/src/boost/tools/build/test/core_action_output.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +# Copyright 2012. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test correct "-p" option handling. + +import BoostBuild + +t = BoostBuild.Tester(["-d1"], pass_toolset=False) + +t.write("file.jam", """\ +prefix = "echo \\"" ; +suffix = "\\"" ; +if $(NT) +{ + prefix = "(echo " ; + suffix = ")" ; +} +actions go +{ + $(prefix)stdout$(suffix) + $(prefix)stderr$(suffix) 1>&2 +} +ECHO "{{{" $(XXX) "}}}" ; +ALWAYS all ; +go all ; +""") + +t.run_build_system(["-ffile.jam", "-sXXX=1"], stderr="") +t.expect_output_lines("{{{ 1 }}}") +t.expect_output_lines("stdout") +t.expect_output_lines("stderr") +t.expect_nothing_more() + +t.run_build_system(["-ffile.jam", "-sXXX=2", "-p0"], stderr="") +t.expect_output_lines("{{{ 2 }}}") +t.expect_output_lines("stdout") +t.expect_output_lines("stderr") +t.expect_nothing_more() + +t.run_build_system(["-ffile.jam", "-sXXX=3", "-p1"], stderr="") +t.expect_output_lines("{{{ 3 }}}") +t.expect_output_lines("stdout") +t.expect_output_lines("stderr*", False) +t.expect_nothing_more() + +t.run_build_system(["-ffile.jam", "-sXXX=4", "-p2"], stderr="stderr\n") +t.expect_output_lines("{{{ 4 }}}") +t.expect_output_lines("stdout*", False) +t.expect_output_lines("stderr*", False) +t.expect_nothing_more() + +t.run_build_system(["-ffile.jam", "-sXXX=5", "-p3"], stderr="stderr\n") +t.expect_output_lines("{{{ 5 }}}") +t.expect_output_lines("stdout") +t.expect_output_lines("stderr*", False) +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/core_action_status.py b/src/boost/tools/build/test/core_action_status.py new file mode 100755 index 00000000..7ebd4386 --- /dev/null +++ b/src/boost/tools/build/test/core_action_status.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +# Copyright 2007 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """\ +actions quietly .a. { $(ACTION) } + +rule .a. +{ + DEPENDS $(<) : $(>) ; +} + +NOTFILE subtest ; +.a. subtest_a : subtest ; +DEPENDS all : subtest_a ; +""") + +t.run_build_system(["-ffile.jam", "-sACTION=invalid"], status=1) + +t.cleanup() diff --git a/src/boost/tools/build/test/core_actions_quietly.py b/src/boost/tools/build/test/core_actions_quietly.py new file mode 100755 index 00000000..c020846d --- /dev/null +++ b/src/boost/tools/build/test/core_actions_quietly.py @@ -0,0 +1,61 @@ +#!/usr/bin/python + +# Copyright 2007 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """\ +actions quietly .a. +{ +echo [$(<:B)] 0 +echo [$(<:B)] 1 +echo [$(<:B)] 2 +} + +rule .a. +{ + DEPENDS $(<) : $(>) ; +} + +NOTFILE subtest ; +.a. subtest_a : subtest ; +.a. subtest_b : subtest ; +DEPENDS all : subtest_a subtest_b ; +""") + +t.run_build_system(["-ffile.jam", "-d2"], stdout="""\ +...found 4 targets... +...updating 2 targets... +.a. subtest_a + +echo [subtest_a] 0 +echo [subtest_a] 1 +echo [subtest_a] 2 + +[subtest_a] 0 +[subtest_a] 1 +[subtest_a] 2 +.a. subtest_b + +echo [subtest_b] 0 +echo [subtest_b] 1 +echo [subtest_b] 2 + +[subtest_b] 0 +[subtest_b] 1 +[subtest_b] 2 +...updated 2 targets... +""") + +t.run_build_system(["-ffile.jam", "-d1"], stdout="""\ +...found 4 targets... +...updating 2 targets... +...updated 2 targets... +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_arguments.py b/src/boost/tools/build/test/core_arguments.py new file mode 100755 index 00000000..1e0bd4b0 --- /dev/null +++ b/src/boost/tools/build/test/core_arguments.py @@ -0,0 +1,103 @@ +#!/usr/bin/python + +# Copyright 2001 Dave Abrahams +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + + +def simple_args(start, finish): + return " : ".join("%d" % x for x in range(start, finish + 1)) + + +def test(t, type, input, output, status=0): + code = ["include echo_args.jam ; echo_%s" % type] + if input: code.append(input) + code.append(";") + t.write("file.jam", " ".join(code)) + t.run_build_system(["-ffile.jam"], status=status) + t.expect_output_lines(output) + + +def test_args(t, *args, **kwargs): + test(t, "args", *args, **kwargs) + + +def test_varargs(t, *args, **kwargs): + test(t, "varargs", *args, **kwargs) + + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("echo_args.jam", """\ +NOCARE all ; + +rule echo_args ( a b ? c ? : d + : e * ) +{ + ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) ; +} + +rule echo_varargs ( a b ? c ? : d + : e * : * ) +{ + ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) + ": rest= "$(4[1]) $(4[2-]) + ": "$(5[1]) $(5[2-]) ": "$(6[1]) $(6[2-]) ": "$(7[1]) $(7[2-]) + ": "$(8[1]) $(8[2-]) ": "$(9[1]) $(9[2-]) ": "$(10[1]) $(10[2-]) + ": "$(11[1]) $(11[2-]) ": "$(12[1]) $(12[2-]) ": "$(13[1]) $(13[2-]) + ": "$(14[1]) $(14[2-]) ": "$(15[1]) $(15[2-]) ": "$(16[1]) $(16[2-]) + ": "$(17[1]) $(17[2-]) ": "$(18[1]) $(18[2-]) ": "$(19[1]) $(19[2-]) + ": "$(20[1]) $(20[2-]) ": "$(21[1]) $(21[2-]) ": "$(22[1]) $(22[2-]) + ": "$(23[1]) $(23[2-]) ": "$(24[1]) $(24[2-]) ": "$(25[1]) $(25[2-]) ; +} +""") + +test_args(t, "", "* missing argument a", status=1) +test_args(t, "1 2 : 3 : 4 : 5", "* extra argument 5", status=1) +test_args(t, "a b c1 c2 : d", "* extra argument c2", status=1) + +# Check modifier '?' +test_args(t, "1 2 3 : 4", "a= 1 b= 2 c= 3 : d= 4 : e=") +test_args(t, "1 2 : 3", "a= 1 b= 2 c= : d= 3 : e=") +test_args(t, "1 2 : 3", "a= 1 b= 2 c= : d= 3 : e=") +test_args(t, "1 : 2", "a= 1 b= c= : d= 2 : e=") + +# Check modifier '+' +test_args(t, "1", "* missing argument d", status=1) +test_args(t, "1 : 2 3", "a= 1 b= c= : d= 2 3 : e=") +test_args(t, "1 : 2 3 4", "a= 1 b= c= : d= 2 3 4 : e=") + +# Check modifier '*' +test_args(t, "1 : 2 : 3", "a= 1 b= c= : d= 2 : e= 3") +test_args(t, "1 : 2 : 3 4", "a= 1 b= c= : d= 2 : e= 3 4") +test_args(t, "1 : 2 : 3 4 5", "a= 1 b= c= : d= 2 : e= 3 4 5") + +# Check varargs +test_varargs(t, "1 : 2 : 3 4 5", "a= 1 b= c= : d= 2 : e= 3 4 5") +test_varargs(t, "1 : 2 : 3 4 5 : 6", "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6") +test_varargs(t, "1 : 2 : 3 4 5 : 6 7", + "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7") +test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8", + "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8") +test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8 : 9", + "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : 9") +test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : " + "16 : 17 : 18 : 19a 19b", "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : " + "9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19a 19b") +test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : " + "16 : 17 : 18 : 19a 19b 19c : 20", "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= " + "6 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19a 19b 19c : " + "20") + +# Check varargs upper limit +expected = "a= 1 b= c= : d= 2 : e= 3 : rest= " + simple_args(4, 19) +test_varargs(t, simple_args(1, 19), expected) +test_varargs(t, simple_args(1, 19) + " 19b 19c 19d", expected + " 19b 19c 19d") +test_varargs(t, simple_args(1, 19) + " 19b 19c 19d : 20", expected + " 19b " + "19c 19d") +test_varargs(t, simple_args(1, 20), expected) +test_varargs(t, simple_args(1, 50), expected) + +t.cleanup() diff --git a/src/boost/tools/build/test/core_at_file.py b/src/boost/tools/build/test/core_at_file.py new file mode 100755 index 00000000..50fa5122 --- /dev/null +++ b/src/boost/tools/build/test/core_at_file.py @@ -0,0 +1,63 @@ +#!/usr/bin/python + +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + + +import BoostBuild + +t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) + +t.write("file.jam", """\ +name = n1 n2 ; +contents = M1 M2 ; +EXIT "file:" "@(o$(name) .txt:E= test -D$(contents))" : 0 ; +""") + +t.run_build_system() +t.expect_output_lines("file: on1 on2 .txt"); +t.expect_addition("on1 on2 .txt") +t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True) + +t.rm(".") + +t.write("file.jam", """\ +name = n1 n2 ; +contents = M1 M2 ; +actions run { echo file: "@(o$(name) .txt:E= test -D$(contents))" } +run all ; +""") + +t.run_build_system(["-d2"]) +t.expect_output_lines(' echo file: "on1 on2 .txt" '); +t.expect_addition("on1 on2 .txt") +t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True) + +t.rm(".") + +t.write("file.jam", """\ +name = n1 n2 ; +contents = M1 M2 ; +file = "@($(STDOUT):E= test -D$(contents)\n)" ; +actions run { $(file) } +run all ; +""") + +t.run_build_system(["-d1"]) +t.expect_output_lines(" test -DM1 -DM2") + +t.rm(".") + +t.write("file.jam", """\ +name = n1 n2 ; +contents = M1 M2 ; +actions run { @($(STDOUT):E= test -D$(contents)\n) } +run all ; +""") + +t.run_build_system(["-d1"]) +t.expect_output_lines(" test -DM1 -DM2") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_bindrule.py b/src/boost/tools/build/test/core_bindrule.py new file mode 100755 index 00000000..f97a31f5 --- /dev/null +++ b/src/boost/tools/build/test/core_bindrule.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +# Copyright 2001 Dave Abrahams +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +t = BoostBuild.Tester(["-d1"], pass_toolset=0) + +t.write("subdir1/file-to-bind", "# This file intentionally left blank") + +t.write("file.jam", """\ +rule do-nothing ( target : source ) +{ + DEPENDS $(target) : $(source) ; +} +actions quietly do-nothing { } + +# Make a non-file target which depends on a file that exists +NOTFILE fake-target ; +SEARCH on file-to-bind = subdir1 ; + +do-nothing fake-target : file-to-bind ; + +# Set jam up to call our bind-rule +BINDRULE = bind-rule ; + +rule bind-rule ( target : path ) +{ + ECHO "found:" $(target) at $(path) ; +} + +DEPENDS all : fake-target ; +""") + +t.run_build_system(["-ffile.jam"], stdout="""\ +found: all at all +found: file-to-bind at subdir1%sfile-to-bind +...found 3 targets... +""" % os.sep) + +t.cleanup() diff --git a/src/boost/tools/build/test/core_d12.py b/src/boost/tools/build/test/core_d12.py new file mode 100644 index 00000000..370fc4bf --- /dev/null +++ b/src/boost/tools/build/test/core_d12.py @@ -0,0 +1,32 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# This tests correct handling of "-d1" and "-d2" options. + +import BoostBuild + +t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) + +t.write("file.jam", """\ +actions a { } +actions quietly b { } +ALWAYS all ; +a all ; +b all ; +""") + +t.run_build_system(["-d0"], stdout="") + +t.run_build_system(["-d1"]) +t.expect_output_lines("a all") +t.expect_output_lines("b all", False) + +t.run_build_system(["-d2"]) +t.expect_output_lines("a all") +t.expect_output_lines("b all") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_delete_module.py b/src/boost/tools/build/test/core_delete_module.py new file mode 100644 index 00000000..d56ffe6e --- /dev/null +++ b/src/boost/tools/build/test/core_delete_module.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the facilities for deleting modules. + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """ +module foo +{ + rule bar { } + var = x y ; +} +DELETE_MODULE foo ; +if [ RULENAMES foo ] +{ + EXIT DELETE_MODULE failed to kill foo's rules: [ RULENAMES foo ] ; +} + +module foo +{ + if $(var) + { + EXIT DELETE_MODULE failed to kill foo's variables ; + } + + rule bar { } + var = x y ; + + DELETE_MODULE foo ; + + if $(var) + { + EXIT internal DELETE_MODULE failed to kill foo's variables ; + } + if [ RULENAMES foo ] + { + EXIT internal DELETE_MODULE failed to kill foo's rules: [ RULENAMES foo ] ; + } +} +DEPENDS all : xx ; +NOTFILE xx ; +""") + +t.run_build_system(["-ffile.jam"], status=0) +t.cleanup() diff --git a/src/boost/tools/build/test/core_dependencies.py b/src/boost/tools/build/test/core_dependencies.py new file mode 100644 index 00000000..4c60537d --- /dev/null +++ b/src/boost/tools/build/test/core_dependencies.py @@ -0,0 +1,157 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests correct handling of dependencies, specifically, on generated +# sources, and from generated sources. + +import BoostBuild + +import string + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("core-dependency-helpers", """ +rule hdrrule +{ + INCLUDES $(1) : $(2) ; +} +actions copy +{ + cp $(>) $(<) +} +""") + +code = """include core-dependency-helpers ; +DEPENDS all : a ; +DEPENDS a : b ; + +actions create-b +{ + echo '#include <foo.h>' > $(<) +} +copy a : b ; +create-b b ; +HDRRULE on b foo.h bar.h = hdrrule ; +HDRSCAN on b foo.h bar.h = \"#include <(.*)>\" ; +""" + +# This creates 'a' which depends on 'b', which is generated. The generated 'b' +# contains '#include <foo.h>' and no rules for foo.h are given. The system +# should error out on the first invocation. +t.run_build_system("-f-", stdin=code) +t.fail_test(t.stdout().find("...skipped a for lack of foo.h...") == -1) + +t.rm('b') + +# Now test that if target 'c' also depends on 'b', then it will not be built, as +# well. +t.run_build_system("-f-", stdin=code + " copy c : b ; DEPENDS c : b ; DEPENDS all : c ; ") +t.fail_test(t.stdout().find("...skipped c for lack of foo.h...") == -1) + +t.rm('b') + +# Now add a rule for creating foo.h. +code += """ +actions create-foo +{ + echo // > $(<) +} +create-foo foo.h ; +""" +t.run_build_system("-f-", stdin=code) + +# Run two times, adding explicit dependency from all to foo.h at the beginning +# and at the end, to make sure that foo.h is generated before 'a' in all cases. + +def mk_correct_order_func(s1, s2): + def correct_order(s): + n1 = s.find(s1) + n2 = s.find(s2) + return ( n1 != -1 ) and ( n2 != -1 ) and ( n1 < n2 ) + return correct_order + +correct_order = mk_correct_order_func("create-foo", "copy a") + +t.rm(["a", "b", "foo.h"]) +t.run_build_system("-d+2 -f-", stdin=code + " DEPENDS all : foo.h ;") +t.fail_test(not correct_order(t.stdout())) + +t.rm(["a", "b", "foo.h"]) +t.run_build_system("-d+2 -f-", stdin=" DEPENDS all : foo.h ; " + code) +t.fail_test(not correct_order(t.stdout())) + +# Now foo.h exists. Test include from b -> foo.h -> bar.h -> biz.h. b and foo.h +# already have updating actions. +t.rm(["a", "b"]) +t.write("foo.h", "#include <bar.h>") +t.write("bar.h", "#include <biz.h>") +t.run_build_system("-d+2 -f-", stdin=code) +t.fail_test(t.stdout().find("...skipped a for lack of biz.h...") == -1) + +# Add an action for biz.h. +code += """ +actions create-biz +{ + echo // > $(<) +} +create-biz biz.h ; +""" + +t.rm(["b"]) +correct_order = mk_correct_order_func("create-biz", "copy a") +t.run_build_system("-d+2 -f-", stdin=code + " DEPENDS all : biz.h ;") +t.fail_test(not correct_order(t.stdout())) + +t.rm(["a", "biz.h"]) +t.run_build_system("-d+2 -f-", stdin=" DEPENDS all : biz.h ; " + code) +t.fail_test(not correct_order(t.stdout())) + +t.write("a", "") + +code=""" +DEPENDS all : main d ; + +actions copy +{ + cp $(>) $(<) ; +} + +DEPENDS main : a ; +copy main : a ; + +INCLUDES a : <1>c ; + +NOCARE <1>c ; +SEARCH on <1>c = . ; + +actions create-c +{ + echo d > $(<) +} + +actions create-d +{ + echo // > $(<) +} + +create-c <2>c ; +LOCATE on <2>c = . ; +create-d d ; + +HDRSCAN on <1>c = (.*) ; +HDRRULE on <1>c = hdrrule ; + +rule hdrrule +{ + INCLUDES $(1) : d ; +} +""" + +correct_order = mk_correct_order_func("create-d", "copy main") +t.run_build_system("-d2 -f-", stdin=code) +t.fail_test(not correct_order(t.stdout())) + +t.cleanup() diff --git a/src/boost/tools/build/test/core_fail_expected.py b/src/boost/tools/build/test/core_fail_expected.py new file mode 100644 index 00000000..0865a0b7 --- /dev/null +++ b/src/boost/tools/build/test/core_fail_expected.py @@ -0,0 +1,139 @@ +#!/usr/bin/python + +# Copyright 2017 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +def test_basic(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ + actions fail + { + invalid-dd0eeb5899734622 + } + + FAIL_EXPECTED t1 ; + fail t1 ; + + UPDATE t1 ; + """) + + t.run_build_system(["-ffile.jam"]) + t.expect_output_lines("...failed*", False) + t.expect_nothing_more() + + t.cleanup() + +def test_error(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ + actions pass + { + echo okay >$(<) + } + + FAIL_EXPECTED t1 ; + pass t1 ; + + UPDATE t1 ; + """) + + t.run_build_system(["-ffile.jam"], status=1) + t.expect_output_lines("...failed pass t1...") + t.expect_nothing_more() + + t.cleanup() + +def test_multiple_actions(): + """FAIL_EXPECTED targets are considered to pass if the first + updating action fails. Further actions will be skipped.""" + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ + actions fail + { + invalid-dd0eeb5899734622 + } + + actions pass + { + echo okay >$(<) + } + + FAIL_EXPECTED t1 ; + fail t1 ; + pass t1 ; + + UPDATE t1 ; + """) + + t.run_build_system(["-ffile.jam", "-d1"]) + t.expect_output_lines("...failed*", False) + t.expect_output_lines("pass t1", False) + t.expect_nothing_more() + + t.cleanup() + +def test_quitquick(): + """Tests that FAIL_EXPECTED targets do not cause early exit + on failure.""" + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ + actions fail + { + invalid-dd0eeb5899734622 + } + + actions pass + { + echo okay >$(<) + } + + FAIL_EXPECTED t1 ; + fail t1 ; + + pass t2 ; + + UPDATE t1 t2 ; + """) + + t.run_build_system(["-ffile.jam", "-q", "-d1"]) + t.expect_output_lines("pass t2") + t.expect_addition("t2") + t.expect_nothing_more() + + t.cleanup() + +def test_quitquick_error(): + """FAIL_EXPECTED targets should cause early exit if they unexpectedly pass.""" + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ + actions pass + { + echo okay >$(<) + } + + FAIL_EXPECTED t1 ; + pass t1 ; + pass t2 ; + + UPDATE t1 t2 ; + """) + + t.run_build_system(["-ffile.jam", "-q", "-d1"], status=1) + t.expect_output_lines("pass t2", False) + t.expect_nothing_more() + + t.cleanup() + +test_basic() +test_error() +test_multiple_actions() +test_quitquick() +test_quitquick_error() diff --git a/src/boost/tools/build/test/core_import_module.py b/src/boost/tools/build/test/core_import_module.py new file mode 100644 index 00000000..5903dcd6 --- /dev/null +++ b/src/boost/tools/build/test/core_import_module.py @@ -0,0 +1,82 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("code", """\ +module a +{ + rule r1 ( ) + { + ECHO R1 ; + } + + local rule l1 ( ) + { + ECHO A.L1 ; + } +} +module a2 +{ + rule r2 ( ) + { + ECHO R2 ; + } +} +IMPORT a2 : r2 : : a2.r2 ; + +rule a.l1 ( ) +{ + ECHO L1 ; +} + +module b +{ + IMPORT_MODULE a : b ; + rule test + { + # Call rule visible via IMPORT_MODULE + a.r1 ; + # Call rule in global scope + a2.r2 ; + # Call rule in global scope. Doesn't find local rule + a.l1 ; + # Make l1 visible + EXPORT a : l1 ; + a.l1 ; + } +} + +IMPORT b : test : : test ; +test ; + +module c +{ + rule test + { + ECHO CTEST ; + } +} + +IMPORT_MODULE c : ; +c.test ; + +EXIT : 0 ; +""") + +t.run_build_system(["-fcode"], stdout="""\ +R1 +R2 +L1 +A.L1 +CTEST + +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_jamshell.py b/src/boost/tools/build/test/core_jamshell.py new file mode 100644 index 00000000..7020ac0b --- /dev/null +++ b/src/boost/tools/build/test/core_jamshell.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +# Copyright 2014 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import sys + +t = BoostBuild.Tester(pass_toolset=False) + +t.write("file.jam", """ +actions run { + $(ACTION) +} + +# Raw commands only work on Windows +if $(OS) = NT +{ + JAMSHELL on test-raw = % ; + JAMSHELL on test-raw-fail = % ; +} +ACTION on test-raw = "\"$(PYTHON)\" -V" ; +run test-raw ; + +ACTION on test-raw-fail = missing-executable ; +run test-raw-fail ; + +# On Windows, the command is stored in a temporary +# file. On other systems it is passed directly. +if $(OS) = NT +{ + JAMSHELL on test-py = $(PYTHON) ; +} +else +{ + JAMSHELL on test-py = $(PYTHON) -c ; +} +ACTION on test-py = " +from __future__ import print_function +print(\\\",\\\".join([str(x) for x in range(3)])) +" ; +run test-py ; + +DEPENDS all : test-raw test-raw-fail test-py ; +""") + +t.run_build_system(["-ffile.jam", "-d1", "-sPYTHON=" + sys.executable], status=1) +t.expect_output_lines([ + "...failed run test-raw-fail...", + "0,1,2", + "...failed updating 1 target...", + "...updated 2 targets..."]) + +t.cleanup() diff --git a/src/boost/tools/build/test/core_language.py b/src/boost/tools/build/test/core_language.py new file mode 100755 index 00000000..88a6d193 --- /dev/null +++ b/src/boost/tools/build/test/core_language.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) +t.set_tree("core-language") +t.run_build_system(["-ftest.jam"]) +t.cleanup() diff --git a/src/boost/tools/build/test/core_modifiers.py b/src/boost/tools/build/test/core_modifiers.py new file mode 100644 index 00000000..24144358 --- /dev/null +++ b/src/boost/tools/build/test/core_modifiers.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the "existing" and "updated" modifiers on actions. + +import BoostBuild +import string + +t = BoostBuild.Tester(pass_toolset=0) + +code = """ +DEPENDS all : a ; +ALWAYS a ; +NOTFILE a ; + +actions existing make-a +{ + echo $(>) > list +} +make-a a : a-1 a-2 a-3 ; +DEPENDS a : a-1 a-2 a-3 ; +NOCARE a-1 a-2 ; + +actions make-a3 +{ + echo foo > $(<) +} +make-a3 a-3 ; +""" + +t.write("file.jam", code) +t.write("a-1", "") + +t.run_build_system("-ffile.jam") +t.fail_test(string.strip(t.read("list")) != "a-1") +t.rm(["a-3", "list"]) + +code = code.replace("existing", "updated") +t.write("file.jam", code) +t.run_build_system("-ffile.jam") +t.fail_test(string.strip(t.read("list")) != "a-3") + +code = code.replace("updated", "existing updated") +t.write("file.jam", code) +t.run_build_system("-ffile.jam") +t.fail_test(string.strip(t.read("list")) != "a-1 a-3") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_multifile_actions.py b/src/boost/tools/build/test/core_multifile_actions.py new file mode 100755 index 00000000..a9c7f479 --- /dev/null +++ b/src/boost/tools/build/test/core_multifile_actions.py @@ -0,0 +1,202 @@ +#!/usr/bin/python + +# Copyright 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tests that actions that produce multiple targets are handled +# correctly. The rules are as follows: +# +# - If any action that updates a target is run, then the target +# is considered to be out-of-date and all of its updating actions +# are run in order. +# - A target is considered updated when all of its updating actions +# have completed successfully. +# - If any updating action for a target fails, then the remaining +# actions are skipped and the target is marked as failed. +# +# Note that this is a more thorough test case for the same +# problem that core_parallel_multifile_actions_N.py checks for. + +import BoostBuild + +t = BoostBuild.Tester(["-d1"], pass_toolset=0) + +t.write("file.jam", """ +actions update +{ + echo updating $(<) +} + +update x1 x2 ; +update x2 x3 ; +""") + +# Updating x1 should force x2 to update as well. +t.run_build_system(["-ffile.jam", "x1"], stdout="""\ +...found 3 targets... +...updating 3 targets... +update x1 +updating x1 x2 +update x2 +updating x2 x3 +...updated 3 targets... +""") + +# If x1 is up-to-date, we don't need to update x2, +# even though x2 is missing. +t.write("x1", "") +t.run_build_system(["-ffile.jam", "x1"], stdout="""\ +...found 1 target... +""") + +# Building x3 should update x1 and x2, even though +# x1 would be considered up-to-date, taken alone. +t.run_build_system(["-ffile.jam", "x3"], stdout="""\ +...found 3 targets... +...updating 2 targets... +update x1 +updating x1 x2 +update x2 +updating x2 x3 +...updated 3 targets... +""") + +# Updating x2 should succeed, but x3 should be skipped +t.rm("x1") +t.write("file.jam", """\ +actions update +{ + echo updating $(<) +} +actions fail +{ + echo failed $(<) + exit 1 +} + +update x1 x2 ; +fail x1 ; +update x1 x3 ; +update x2 ; +update x3 ; +""") + +t.run_build_system(["-ffile.jam", "x3"], status=1, stdout="""\ +...found 3 targets... +...updating 3 targets... +update x1 +updating x1 x2 +fail x1 +failed x1 + + echo failed x1 + exit 1 + +...failed fail x1... +update x2 +updating x2 +...failed updating 2 targets... +...updated 1 target... +""") + +# Make sure that dependencies of targets that are +# updated as a result of a multifile action are +# processed correctly. +t.rm("x1") +t.write("file.jam", """\ +actions update +{ + echo updating $(<) +} + +update x1 ; +update x2 ; +DEPENDS x2 : x1 ; +update x2 x3 ; +""") +t.run_build_system(["-ffile.jam", "x3"], stdout="""\ +...found 3 targets... +...updating 3 targets... +update x1 +updating x1 +update x2 +updating x2 +update x2 +updating x2 x3 +...updated 3 targets... +""") + +# JAM_SEMAPHORE rules: +# +# - if two updating actions have targets that share a semaphore, +# these actions cannot be run in parallel. +# +t.write("file.jam", """\ +actions update +{ + echo updating $(<) +} + +targets = x1 x2 ; +JAM_SEMAPHORE on $(targets) = <s>update_sem ; +update x1 x2 ; +""") +t.run_build_system(["-ffile.jam", "x1"], stdout="""\ +...found 2 targets... +...updating 2 targets... +update x1 +updating x1 x2 +...updated 2 targets... +""") + +# A target can appear multiple times in an action +t.write("file.jam", """\ +actions update +{ + echo updating $(<) +} + +update x1 x1 ; +""") +t.run_build_system(["-ffile.jam", "x1"], stdout="""\ +...found 1 target... +...updating 1 target... +update x1 +updating x1 x1 +...updated 1 target... +""") + +# Together actions should check that all the targets are the same +# before combining. +t.write("file.jam", """\ +actions together update +{ + echo updating $(<) : $(>) +} + +update x1 x2 : s1 ; +update x1 x2 : s2 ; + +update x3 : s3 ; +update x3 x4 : s4 ; +update x4 x3 : s5 ; +DEPENDS all : x1 x2 x3 x4 ; +""") +t.run_build_system(["-ffile.jam"], stdout="""\ +...found 5 targets... +...updating 4 targets... +update x1 +updating x1 x2 : s1 s2 +update x3 +updating x3 : s3 +update x3 +updating x3 x4 : s4 +update x4 +updating x4 x3 : s5 +...updated 4 targets... +""") + + + +t.cleanup() diff --git a/src/boost/tools/build/test/core_nt_cmd_line.py b/src/boost/tools/build/test/core_nt_cmd_line.py new file mode 100755 index 00000000..be21f6ca --- /dev/null +++ b/src/boost/tools/build/test/core_nt_cmd_line.py @@ -0,0 +1,266 @@ +#!/usr/bin/python + +# Copyright 2001 Dave Abrahams +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests Windows command line construction. +# +# Note that the regular 'echo' is an internal shell command on Windows and +# therefore can not be called directly as a standalone Windows process. + +import BoostBuild +import os +import re +import sys + + +executable = sys.executable.replace("\\", "/") +if " " in executable: + executable = '"%s"' % executable + + +def string_of_length(n): + if n <= 0: + return "" + n -= 1 + y = ['', '$(1x10-1)', '$(10x10-1)', '$(100x10-1)', '$(1000x10-1)'] + result = [] + for i in reversed(range(5)): + x, n = divmod(n, 10 ** i) + result += [y[i]] * x + result.append('x') + return " ".join(result) + + +# Boost Jam currently does not allow preparing actions with completely empty +# content and always requires at least a single whitespace after the opening +# brace in order to satisfy its Boost Jam language grammar rules. +def test_raw_empty(): + whitespace_in = " \n\n\r\r\v\v\t\t \t \r\r \n\n" + + # We tell the testing system to read its child process output as raw + # binary data but the bjam process we run will read its input file and + # write out its output as text, i.e. convert all of our "\r\n" sequences to + # "\n" on input and all of its "\n" characters back to "\r\n" on output. + # This means that any lone "\n" input characters not preceded by "\r" will + # get an extra "\r" added in front of it on output. + whitespace_out = whitespace_in.replace("\r\n", "\n").replace("\n", "\r\n") + + t = BoostBuild.Tester(["-d2", "-d+4"], pass_toolset=0, + use_test_config=False) + t.write("file.jam", """\ +actions do_empty {%s} +JAMSHELL = %% ; +do_empty all ; +""" % (whitespace_in)) + t.run_build_system(["-ffile.jam"], universal_newlines=False) + t.expect_output_lines("do_empty all") + t.expect_output_lines("Executing raw command directly", False) + if "\r\n%s\r\n" % whitespace_out not in t.stdout(): + BoostBuild.annotation("failure", "Whitespace action content not found " + "on stdout.") + t.fail_test(1, dump_difference=False) + t.cleanup() + + +def test_raw_nt(n=None, error=False): + t = BoostBuild.Tester(["-d1", "-d+4"], pass_toolset=0, + use_test_config=False) + + cmd_prefix = "%s -c \"print('XXX: " % executable + cmd_suffix = "')\"" + cmd_extra_length = len(cmd_prefix) + len(cmd_suffix) + + if n == None: + n = cmd_extra_length + + data_length = n - cmd_extra_length + if data_length < 0: + BoostBuild.annotation("failure", """\ +Can not construct Windows command of desired length. Requested command length +too short for the current test configuration. + Requested command length: %d + Minimal supported command length: %d +""" % (n, cmd_extra_length)) + t.fail_test(1, dump_difference=False) + + # Each $(Xx10-1) variable contains X words of 9 characters each, which, + # including spaces between words, brings the total number of characters in + # its string representation to X * 10 - 1 (X * 9 characters + (X - 1) + # spaces). + t.write("file.jam", """\ +ten = 0 1 2 3 4 5 6 7 8 9 ; + +1x10-1 = 123456789 ; +10x10-1 = $(ten)12345678 ; +100x10-1 = $(ten)$(ten)1234567 ; +1000x10-1 = $(ten)$(ten)$(ten)123456 ; + +actions do_echo +{ + %s%s%s +} +JAMSHELL = %% ; +do_echo all ; +""" % (cmd_prefix, string_of_length(data_length), cmd_suffix)) + if error: + expected_status = 1 + else: + expected_status = 0 + t.run_build_system(["-ffile.jam"], status=expected_status) + if error: + t.expect_output_lines("Executing raw command directly", False) + t.expect_output_lines("do_echo action is too long (%d, max 32766):" % n + ) + t.expect_output_lines("XXX: *", False) + else: + t.expect_output_lines("Executing raw command directly") + t.expect_output_lines("do_echo action is too long*", False) + + m = re.search("^XXX: (.*)$", t.stdout(), re.MULTILINE) + if not m: + BoostBuild.annotation("failure", "Expected output line starting " + "with 'XXX: ' not found.") + t.fail_test(1, dump_difference=False) + if len(m.group(1)) != data_length: + BoostBuild.annotation("failure", """Unexpected output data length. + Expected: %d + Received: %d""" % (n, len(m.group(1)))) + t.fail_test(1, dump_difference=False) + + t.cleanup() + + +def test_raw_to_shell_fallback_nt(): + t = BoostBuild.Tester(["-d1", "-d+4"], pass_toolset=0, + use_test_config=False) + + cmd_prefix = '%s -c print(' % executable + cmd_suffix = ')' + + t.write("file_multiline.jam", """\ +actions do_multiline +{ + echo one + + + echo two +} +JAMSHELL = % ; +do_multiline all ; +""") + t.run_build_system(["-ffile_multiline.jam"]) + t.expect_output_lines("do_multiline all") + t.expect_output_lines("one") + t.expect_output_lines("two") + t.expect_output_lines("Executing raw command directly", False) + t.expect_output_lines("Executing using a command file and the shell: " + "cmd.exe /Q/C") + + t.write("file_redirect.jam", """\ +actions do_redirect { echo one > two.txt } +JAMSHELL = % ; +do_redirect all ; +""") + t.run_build_system(["-ffile_redirect.jam"]) + t.expect_output_lines("do_redirect all") + t.expect_output_lines("one", False) + t.expect_output_lines("Executing raw command directly", False) + t.expect_output_lines("Executing using a command file and the shell: " + "cmd.exe /Q/C") + t.expect_addition("two.txt") + + t.write("file_pipe.jam", """\ +actions do_pipe +{ + echo one | echo two +} +JAMSHELL = % ; +do_pipe all ; +""") + t.run_build_system(["-ffile_pipe.jam"]) + t.expect_output_lines("do_pipe all") + t.expect_output_lines("one*", False) + t.expect_output_lines("two") + t.expect_output_lines("Executing raw command directly", False) + t.expect_output_lines("Executing using a command file and the shell: " + "cmd.exe /Q/C") + + t.write("file_single_quoted.jam", """\ +actions do_single_quoted { %s'5>10'%s } +JAMSHELL = %% ; +do_single_quoted all ; +""" % (cmd_prefix, cmd_suffix)) + t.run_build_system(["-ffile_single_quoted.jam"]) + t.expect_output_lines("do_single_quoted all") + t.expect_output_lines("5>10") + t.expect_output_lines("Executing raw command directly") + t.expect_output_lines("Executing using a command file and the shell: " + "cmd.exe /Q/C", False) + t.expect_nothing_more() + + t.write("file_double_quoted.jam", """\ +actions do_double_quoted { %s"5>10"%s } +JAMSHELL = %% ; +do_double_quoted all ; +""" % (cmd_prefix, cmd_suffix)) + t.run_build_system(["-ffile_double_quoted.jam"]) + t.expect_output_lines("do_double_quoted all") + # The difference between this example and the similar previous one using + # single instead of double quotes stems from how the used Python executable + # parses the command-line string received from Windows. + t.expect_output_lines("False") + t.expect_output_lines("Executing raw command directly") + t.expect_output_lines("Executing using a command file and the shell: " + "cmd.exe /Q/C", False) + t.expect_nothing_more() + + t.write("file_escaped_quote.jam", """\ +actions do_escaped_quote { %s\\"5>10\\"%s } +JAMSHELL = %% ; +do_escaped_quote all ; +""" % (cmd_prefix, cmd_suffix)) + t.run_build_system(["-ffile_escaped_quote.jam"]) + t.expect_output_lines("do_escaped_quote all") + t.expect_output_lines("5>10") + t.expect_output_lines("Executing raw command directly", False) + t.expect_output_lines("Executing using a command file and the shell: " + "cmd.exe /Q/C") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +if os.name == 'nt': + test_raw_empty() + + # Can not test much shorter lengths as the shortest possible command line + # line length constructed in this depends on the runtime environment, e.g. + # path to the Panther executable running this test. + test_raw_nt() + test_raw_nt(255) + test_raw_nt(1000) + test_raw_nt(8000) + test_raw_nt(8191) + test_raw_nt(8192) + test_raw_nt(10000) + test_raw_nt(30000) + test_raw_nt(32766) + # CreateProcessA() Windows API places a limit of 32768 on the allowed + # command-line length, including a trailing Unicode (2-byte) nul-terminator + # character. + test_raw_nt(32767, error=True) + test_raw_nt(40000, error=True) + test_raw_nt(100001, error=True) + + test_raw_to_shell_fallback_nt()
\ No newline at end of file diff --git a/src/boost/tools/build/test/core_option_d2.py b/src/boost/tools/build/test/core_option_d2.py new file mode 100755 index 00000000..8e6b05a4 --- /dev/null +++ b/src/boost/tools/build/test/core_option_d2.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +# Copyright 2007 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """\ +actions .a. +{ +echo [$(<:B)] 0 +echo [$(<:B)] 1 +echo [$(<:B)] 2 +} + +rule .a. +{ + DEPENDS $(<) : $(>) ; +} + +NOTFILE subtest ; +.a. subtest_a : subtest ; +.a. subtest_b : subtest ; +DEPENDS all : subtest_a subtest_b ; +""") + +t.run_build_system(["-ffile.jam", "-d2"], stdout="""\ +...found 4 targets... +...updating 2 targets... +.a. subtest_a + +echo [subtest_a] 0 +echo [subtest_a] 1 +echo [subtest_a] 2 + +[subtest_a] 0 +[subtest_a] 1 +[subtest_a] 2 +.a. subtest_b + +echo [subtest_b] 0 +echo [subtest_b] 1 +echo [subtest_b] 2 + +[subtest_b] 0 +[subtest_b] 1 +[subtest_b] 2 +...updated 2 targets... +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_option_l.py b/src/boost/tools/build/test/core_option_l.py new file mode 100755 index 00000000..e237dcf6 --- /dev/null +++ b/src/boost/tools/build/test/core_option_l.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +# Copyright 2007 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("sleep.bat", """\ +::@timeout /T %1 /NOBREAK >nul +@ping 127.0.0.1 -n 2 -w 1000 >nul +@ping 127.0.0.1 -n %1 -w 1000 >nul +@exit /B 0 +""") + +t.write("file.jam", """\ +if $(NT) +{ + SLEEP = @call sleep.bat ; +} +else +{ + SLEEP = sleep ; +} + +actions .a. { +echo 001 +$(SLEEP) 4 +echo 002 +} + +.a. sleeper ; + +DEPENDS all : sleeper ; +""") + +t.run_build_system(["-ffile.jam", "-d1", "-l2"], status=1) +t.expect_output_lines("2 second time limit exceeded") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_option_n.py b/src/boost/tools/build/test/core_option_n.py new file mode 100755 index 00000000..af3ee0c3 --- /dev/null +++ b/src/boost/tools/build/test/core_option_n.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright 2007 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """\ +actions .a. +{ +echo [$(<:B)] 0 +echo [$(<:B)] 1 +echo [$(<:B)] 2 +} + +rule .a. +{ + DEPENDS $(<) : $(>) ; +} + +NOTFILE subtest ; +.a. subtest_a : subtest ; +.a. subtest_b : subtest ; +FAIL_EXPECTED subtest_b ; +DEPENDS all : subtest_a subtest_b ; +""") + +t.run_build_system(["-ffile.jam", "-n"], stdout="""\ +...found 4 targets... +...updating 2 targets... +.a. subtest_a + +echo [subtest_a] 0 +echo [subtest_a] 1 +echo [subtest_a] 2 + +.a. subtest_b + +echo [subtest_b] 0 +echo [subtest_b] 1 +echo [subtest_b] 2 + +...updated 2 targets... +""") +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/core_parallel_actions.py b/src/boost/tools/build/test/core_parallel_actions.py new file mode 100755 index 00000000..4f1627c2 --- /dev/null +++ b/src/boost/tools/build/test/core_parallel_actions.py @@ -0,0 +1,103 @@ +#!/usr/bin/python + +# Copyright 2006 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(["-d1"], pass_toolset=0) + +t.write("sleep.bat", """\ +::@timeout /T %1 /NOBREAK >nul +@ping 127.0.0.1 -n 2 -w 1000 >nul +@ping 127.0.0.1 -n %1 -w 1000 >nul +@exit /B 0 +""") + +t.write("file.jam", """\ +if $(NT) +{ + actions sleeper + { + echo [$(<:S)] 0 + call sleep.bat 1 + echo [$(<:S)] 1 + call sleep.bat 1 + echo [$(<:S)] 2 + call sleep.bat $(<:B) + } +} +else +{ + actions sleeper + { + echo "[$(<:S)] 0" + sleep 1 + echo "[$(<:S)] 1" + sleep 1 + echo "[$(<:S)] 2" + sleep $(<:B) + } +} + +rule sleeper +{ + DEPENDS $(<) : $(>) ; +} + +NOTFILE front ; +sleeper 1.a : front ; +sleeper 2.a : front ; +sleeper 3.a : front ; +sleeper 4.a : front ; +NOTFILE choke ; +DEPENDS choke : 1.a 2.a 3.a 4.a ; +sleeper 1.b : choke ; +sleeper 2.b : choke ; +sleeper 3.b : choke ; +sleeper 4.b : choke ; +DEPENDS bottom : 1.b 2.b 3.b 4.b ; +DEPENDS all : bottom ; +""") + +t.run_build_system(["-ffile.jam", "-j4"], stdout="""\ +...found 12 targets... +...updating 8 targets... +sleeper 1.a +[.a] 0 +[.a] 1 +[.a] 2 +sleeper 2.a +[.a] 0 +[.a] 1 +[.a] 2 +sleeper 3.a +[.a] 0 +[.a] 1 +[.a] 2 +sleeper 4.a +[.a] 0 +[.a] 1 +[.a] 2 +sleeper 1.b +[.b] 0 +[.b] 1 +[.b] 2 +sleeper 2.b +[.b] 0 +[.b] 1 +[.b] 2 +sleeper 3.b +[.b] 0 +[.b] 1 +[.b] 2 +sleeper 4.b +[.b] 0 +[.b] 1 +[.b] 2 +...updated 8 targets... +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_parallel_multifile_actions_1.py b/src/boost/tools/build/test/core_parallel_multifile_actions_1.py new file mode 100755 index 00000000..4b800a78 --- /dev/null +++ b/src/boost/tools/build/test/core_parallel_multifile_actions_1.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +# Copyright 2007 Rene Rivera. +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Added to guard against a bug causing targets to be used before they +# themselves have finished building. This used to happen for targets built by a +# multi-file action that got triggered by another target. +# +# Example: +# When target A and target B were declared as created by a single action and +# target A triggered running that action then, while the action was still +# running, target B was already reporting as being built causing other targets +# depending on target A to be built prematurely. + +import BoostBuild + +t = BoostBuild.Tester(["-d1"], pass_toolset=0) + +t.write("sleep.bat", """\ +::@timeout /T %1 /NOBREAK >nul +@ping 127.0.0.1 -n 2 -w 1000 >nul +@ping 127.0.0.1 -n %1 -w 1000 >nul +@exit /B 0 +""") + +t.write("file.jam", """\ +if $(NT) +{ + SLEEP = @call sleep.bat ; +} +else +{ + SLEEP = sleep ; +} + +actions .gen. +{ + echo 001 + $(SLEEP) 4 + echo 002 +} +rule .use.1 { DEPENDS $(<) : $(>) ; } +actions .use.1 +{ + echo 003 +} + +rule .use.2 { DEPENDS $(<) : $(>) ; } +actions .use.2 +{ + $(SLEEP) 1 + echo 004 +} + +.gen. g1.generated g2.generated ; +.use.1 u1.user : g1.generated ; +.use.2 u2.user : g2.generated ; + +DEPENDS all : u1.user u2.user ; +""") + +t.run_build_system(["-ffile.jam", "-j2"], stdout="""\ +...found 5 targets... +...updating 4 targets... +.gen. g1.generated +001 +002 +.use.1 u1.user +003 +.use.2 u2.user +004 +...updated 4 targets... +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_parallel_multifile_actions_2.py b/src/boost/tools/build/test/core_parallel_multifile_actions_2.py new file mode 100755 index 00000000..c49e9238 --- /dev/null +++ b/src/boost/tools/build/test/core_parallel_multifile_actions_2.py @@ -0,0 +1,71 @@ +#!/usr/bin/python + +# Copyright 2008 Jurko Gospodnetic, Vladimir Prus +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Added to guard against a bug causing targets to be used before they +# themselves have finished building. This used to happen for targets built by a +# multi-file action that got triggered by another target, except when the +# target triggering the action was the first one in the list of targets +# produced by that action. +# +# Example: +# When target A and target B were declared as created by a single action with +# A being the first one listed, and target B triggered running that action +# then, while the action was still running, target A was already reporting as +# being built causing other targets depending on target A to be built +# prematurely. + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("sleep.bat", """\ +::@timeout /T %1 /NOBREAK >nul +@ping 127.0.0.1 -n 2 -w 1000 >nul +@ping 127.0.0.1 -n %1 -w 1000 >nul +@exit /B 0 +""") + +t.write("file.jam", """\ +if $(NT) +{ + SLEEP = @call sleep.bat ; +} +else +{ + SLEEP = sleep ; +} + +actions link +{ + $(SLEEP) 1 + echo 001 - linked +} + +link dll lib ; + +actions install +{ + echo 002 - installed +} + +install installed_dll : dll ; +DEPENDS installed_dll : dll ; + +DEPENDS all : lib installed_dll ; +""") + +t.run_build_system(["-ffile.jam", "-j2"], stdout="""\ +...found 4 targets... +...updating 3 targets... +link dll +001 - linked +install installed_dll +002 - installed +...updated 3 targets... +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_scanner.py b/src/boost/tools/build/test/core_scanner.py new file mode 100644 index 00000000..af078a00 --- /dev/null +++ b/src/boost/tools/build/test/core_scanner.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the parsing of tokens + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """\ +rule test1 ( args * ) +{ + EXIT $(args) : 0 ; +} + +test1 +a # a comment +# another comment +b +c #| a multiline comment |# d +#| another +multiline +comment +|# +e "#f" ; +""") + +t.run_build_system(["-ffile.jam"], stdout="""\ +a b c d e #f +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_source_line_tracking.py b/src/boost/tools/build/test/core_source_line_tracking.py new file mode 100755 index 00000000..61526a2c --- /dev/null +++ b/src/boost/tools/build/test/core_source_line_tracking.py @@ -0,0 +1,74 @@ +#!/usr/bin/python + +# Copyright 2012. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test Boost Jam parser's source line tracking & reporting. + +import BoostBuild + + +def test_eof_in_string(): + t = BoostBuild.Tester(pass_toolset=False) + t.write("file.jam", '\n\n\naaa = "\n\n\n\n\n\n') + t.run_build_system(["-ffile.jam"], status=1) + t.expect_output_lines('file.jam:4: unmatched " in string at keyword =') + t.expect_output_lines("file.jam:4: syntax error at EOF") + t.cleanup() + + +def test_error_missing_argument(eof): + """ + This use case used to cause a missing argument error to be reported in + module '(builtin)' in line -1 when the input file did not contain a + trailing newline. + + """ + t = BoostBuild.Tester(pass_toolset=False) + t.write("file.jam", """\ +rule f ( param ) { } +f ;%s""" % __trailing_newline(eof)) + t.run_build_system(["-ffile.jam"], status=1) + t.expect_output_lines("file.jam:2: in module scope") + t.expect_output_lines("file.jam:1:see definition of rule 'f' being called") + t.cleanup() + + +def test_error_syntax(eof): + t = BoostBuild.Tester(pass_toolset=False) + t.write("file.jam", "ECHO%s" % __trailing_newline(eof)) + t.run_build_system(["-ffile.jam"], status=1) + t.expect_output_lines("file.jam:1: syntax error at EOF") + t.cleanup() + + +def test_traceback(): + t = BoostBuild.Tester(pass_toolset=False) + t.write("file.jam", """\ +NOTFILE all ; +ECHO [ BACKTRACE ] ;""") + t.run_build_system(["-ffile.jam"]) + t.expect_output_lines("file.jam 2 module scope") + t.cleanup() + + +def __trailing_newline(eof): + """ + Helper function returning an empty string or a newling character to + append to the current output line depending on whether we want that line to + be the last line in the file (eof == True) or not (eof == False). + + """ + if eof: + return "" + return "\n" + + +test_error_missing_argument(eof=False) +test_error_missing_argument(eof=True) +test_error_syntax(eof=False) +test_error_syntax(eof=True) +test_traceback() +test_eof_in_string() diff --git a/src/boost/tools/build/test/core_typecheck.py b/src/boost/tools/build/test/core_typecheck.py new file mode 100644 index 00000000..de1bece1 --- /dev/null +++ b/src/boost/tools/build/test/core_typecheck.py @@ -0,0 +1,47 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the typechecking facilities. + +import BoostBuild + +t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0) + +t.write("file.jam", """ +module .typecheck +{ + rule "[path]" ( x ) + { + if ! [ MATCH "^(::)" : $(x) ] + { + ECHO "Error: $(x) is not a path" ; + return true ; + } + } +} + +rule do ( [path] a ) +{ +} + +do $(ARGUMENT) ; + +actions dummy { } +dummy all ; +""") + +t.run_build_system(["-sARGUMENT=::a/b/c"]) +t.run_build_system(["-sARGUMENT=a/b/c"], status=1, stdout="""\ +Error: a/b/c is not a path +file.jam:18: in module scope +*** argument error +* rule do ( [path] a ) +* called with: ( a/b/c ) +* true a +file.jam:16:see definition of rule 'do' being called +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/core_update_now.py b/src/boost/tools/build/test/core_update_now.py new file mode 100755 index 00000000..627594bf --- /dev/null +++ b/src/boost/tools/build/test/core_update_now.py @@ -0,0 +1,377 @@ +#!/usr/bin/python + +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + + +def basic(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +actions do-print +{ + echo updating $(<) +} + +NOTFILE target1 ; +ALWAYS target1 ; +do-print target1 ; + +UPDATE_NOW target1 ; + +DEPENDS all : target1 ; +""") + + t.run_build_system(["-ffile.jam"], stdout="""\ +...found 1 target... +...updating 1 target... +do-print target1 +updating target1 +...updated 1 target... +...found 1 target... +""") + + t.cleanup() + + +def ignore_minus_n(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +actions do-print +{ + echo updating $(<) +} + +NOTFILE target1 ; +ALWAYS target1 ; +do-print target1 ; + +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 ; +""") + + t.run_build_system(["-ffile.jam", "-n"], stdout="""\ +...found 1 target... +...updating 1 target... +do-print target1 + + echo updating target1 + +updating target1 +...updated 1 target... +...found 1 target... +""") + + t.cleanup() + + +def failed_target(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +actions fail +{ + exit 1 +} + +NOTFILE target1 ; +ALWAYS target1 ; +fail target1 ; + +actions do-print +{ + echo updating $(<) +} + +NOTFILE target2 ; +do-print target2 ; +DEPENDS target2 : target1 ; + +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 target2 ; +""") + + t.run_build_system(["-ffile.jam", "-n"], stdout="""\ +...found 1 target... +...updating 1 target... +fail target1 + + exit 1 + +...failed fail target1... +...failed updating 1 target... +...found 2 targets... +...updating 1 target... +do-print target2 + + echo updating target2 + +...updated 1 target... +""") + + t.cleanup() + + +def missing_target(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +actions do-print +{ + echo updating $(<) +} + +NOTFILE target2 ; +do-print target2 ; +DEPENDS target2 : target1 ; + +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 target2 ; +""") + + t.run_build_system(["-ffile.jam", "-n"], status=1, stdout="""\ +don't know how to make target1 +...found 1 target... +...can't find 1 target... +...found 2 targets... +...can't make 1 target... +""") + + t.cleanup() + + +def build_once(): + """ + Make sure that if we call UPDATE_NOW with ignore-minus-n, the target gets + updated exactly once regardless of previous calls to UPDATE_NOW with -n in + effect. + + """ + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +actions do-print +{ + echo updating $(<) +} + +NOTFILE target1 ; +ALWAYS target1 ; +do-print target1 ; + +UPDATE_NOW target1 ; +UPDATE_NOW target1 : : ignore-minus-n ; +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 ; +""") + + t.run_build_system(["-ffile.jam", "-n"], stdout="""\ +...found 1 target... +...updating 1 target... +do-print target1 + + echo updating target1 + +...updated 1 target... +do-print target1 + + echo updating target1 + +updating target1 +...updated 1 target... +...found 1 target... +""") + + t.cleanup() + + +def return_status(): + """ + Make sure that UPDATE_NOW returns a failure status if + the target failed in a previous call to UPDATE_NOW + """ + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +actions fail +{ + exit 1 +} + +NOTFILE target1 ; +ALWAYS target1 ; +fail target1 ; + +ECHO "update1:" [ UPDATE_NOW target1 ] ; +ECHO "update2:" [ UPDATE_NOW target1 ] ; + +DEPENDS all : target1 ; +""") + + t.run_build_system(["-ffile.jam"], status=1, stdout="""\ +...found 1 target... +...updating 1 target... +fail target1 + + exit 1 + +...failed fail target1... +...failed updating 1 target... +update1: +update2: +...found 1 target... +""") + + t.cleanup() + + +def save_restore(): + """Tests that ignore-minus-n and ignore-minus-q are + local to the call to UPDATE_NOW""" + t = BoostBuild.Tester(pass_toolset=0) + + t.write("actions.jam", """\ +rule fail +{ + NOTFILE $(<) ; + ALWAYS $(<) ; +} +actions fail +{ + exit 1 +} + +rule pass +{ + NOTFILE $(<) ; + ALWAYS $(<) ; +} +actions pass +{ + echo updating $(<) +} +""") + t.write("file.jam", """ +include actions.jam ; +fail target1 ; +fail target2 ; +UPDATE_NOW target1 target2 : : $(IGNORE_MINUS_N) : $(IGNORE_MINUS_Q) ; +fail target3 ; +fail target4 ; +UPDATE_NOW target3 target4 ; +UPDATE ; +""") + t.run_build_system(['-n', '-sIGNORE_MINUS_N=1', '-ffile.jam'], + stdout='''...found 2 targets... +...updating 2 targets... +fail target1 + + exit 1 + +...failed fail target1... +fail target2 + + exit 1 + +...failed fail target2... +...failed updating 2 targets... +...found 2 targets... +...updating 2 targets... +fail target3 + + exit 1 + +fail target4 + + exit 1 + +...updated 2 targets... +''') + + t.run_build_system(['-q', '-sIGNORE_MINUS_N=1', '-ffile.jam'], + status=1, stdout='''...found 2 targets... +...updating 2 targets... +fail target1 + + exit 1 + +...failed fail target1... +...failed updating 1 target... +...found 2 targets... +...updating 2 targets... +fail target3 + + exit 1 + +...failed fail target3... +...failed updating 1 target... +''') + + t.run_build_system(['-n', '-sIGNORE_MINUS_Q=1', '-ffile.jam'], + stdout='''...found 2 targets... +...updating 2 targets... +fail target1 + + exit 1 + +fail target2 + + exit 1 + +...updated 2 targets... +...found 2 targets... +...updating 2 targets... +fail target3 + + exit 1 + +fail target4 + + exit 1 + +...updated 2 targets... +''') + + t.run_build_system(['-q', '-sIGNORE_MINUS_Q=1', '-ffile.jam'], + status=1, stdout='''...found 2 targets... +...updating 2 targets... +fail target1 + + exit 1 + +...failed fail target1... +fail target2 + + exit 1 + +...failed fail target2... +...failed updating 2 targets... +...found 2 targets... +...updating 2 targets... +fail target3 + + exit 1 + +...failed fail target3... +...failed updating 1 target... +''') + + t.cleanup() + + +basic() +ignore_minus_n() +failed_target() +missing_target() +build_once() +return_status() +save_restore() diff --git a/src/boost/tools/build/test/core_variables_in_actions.py b/src/boost/tools/build/test/core_variables_in_actions.py new file mode 100755 index 00000000..77834f43 --- /dev/null +++ b/src/boost/tools/build/test/core_variables_in_actions.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +# Copyright 2012. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that variables in actions get expanded but double quote characters +# get treated as regular characters and not string literal delimiters when +# determining string tokens concatenated to the variable being expanded. +# +# We also take care to make this test work correctly when run using both +# Windows and Unix echo command variant. That is why we add the extra single +# quotes around the text being echoed - they will make the double quotes be +# displayed as regular characters in both cases but will be displayed +# themselves only when using the Windows cmd shell's echo command. + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) +t.write("file.jam", """\ +rule dummy ( i ) +{ + local a = 1 2 3 ; + ECHO From "rule:" $(a)" seconds" ; + a on $(i) = $(a) ; +} + +actions dummy +{ + echo 'From action: $(a)" seconds"' +} + +dummy all ; +""") +t.run_build_system(["-ffile.jam", "-d1"]) +t.expect_output_lines("From rule: 1 seconds 2 seconds 3 seconds") +t.expect_output_lines('*From action: 1" 2" 3" seconds"*') +t.cleanup() diff --git a/src/boost/tools/build/test/core_varnames.py b/src/boost/tools/build/test/core_varnames.py new file mode 100644 index 00000000..6b61ffcd --- /dev/null +++ b/src/boost/tools/build/test/core_varnames.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This tests the core rule for enumerating the variable names in a module. + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("file.jam", """\ +module foo +{ + rule bar { } + var1 = x y ; + var2 = fubar ; +} + +expected = var1 var2 ; +names = [ VARNAMES foo ] ; +if $(names) in $(expected) && $(expected) in $(names) +{ + # everything OK +} +else +{ + EXIT expected to find variables $(expected:J=", ") in module foo, + but found $(names:J=", ") instead. ; +} +DEPENDS all : xx ; +NOTFILE xx ; +""") + +t.run_build_system(["-ffile.jam"], status=0) + +t.cleanup() diff --git a/src/boost/tools/build/test/custom_generator.py b/src/boost/tools/build/test/custom_generator.py new file mode 100644 index 00000000..00860f64 --- /dev/null +++ b/src/boost/tools/build/test/custom_generator.py @@ -0,0 +1,66 @@ +#!/usr/bin/python + +# Copyright 2003, 2004, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Attempt to declare a generator for creating OBJ from RC files. That generator +# should be considered together with standard CPP->OBJ generators and +# successfully create the target. Since we do not have a RC compiler everywhere, +# we fake the action. The resulting OBJ will be unusable, but it must be +# created. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """ +import rcc ; +""") + +t.write("rcc.jam", """ +import type ; +import generators ; +import print ; + +# Use 'RCC' to avoid conflicts with definitions in the standard rc.jam and +# msvc.jam +type.register RCC : rcc ; + +rule resource-compile ( targets * : sources * : properties * ) +{ + print.output $(targets[1]) ; + print.text "rc-object" ; +} + +generators.register-standard rcc.resource-compile : RCC : OBJ ; +""") + +t.write("rcc.py", """ +import b2.build.type as type +import b2.build.generators as generators + +from b2.manager import get_manager + +# Use 'RCC' to avoid conflicts with definitions in the standard rc.jam and +# msvc.jam +type.register('RCC', ['rcc']) + +generators.register_standard("rcc.resource-compile", ["RCC"], ["OBJ"]) + +get_manager().engine().register_action( + "rcc.resource-compile", + '@($(STDOUT):E=rc-object) > "$(<)"') +""") + +t.write("jamfile.jam", """ +obj r : r.rcc ; +""") + +t.write("r.rcc", """ +""") + +t.run_build_system() +t.expect_content("bin/r.obj", "rc-object") + +t.cleanup() diff --git a/src/boost/tools/build/test/debugger-mi.py b/src/boost/tools/build/test/debugger-mi.py new file mode 100644 index 00000000..fda2bd80 --- /dev/null +++ b/src/boost/tools/build/test/debugger-mi.py @@ -0,0 +1,326 @@ +#!/usr/bin/python + +# Copyright 2016 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the mi interface for the debugger + +import BoostBuild +import TestCmd +import re + +def split_stdin_stdout(text): + """stdin is all text after the prompt up to and including + the next newline. Everything else is stdout. stdout + may contain regular expressions enclosed in {{}}.""" + prompt = re.escape('(gdb) \n') + pattern = re.compile('(?<=%s)((?:\d*-.*)\n)' % prompt) + stdin = ''.join(re.findall(pattern, text)) + stdout = re.sub(pattern, '', text) + outside_pattern = re.compile(r'(?:\A|(?<=\}\}))(?:[^\{]|(?:\{(?!\{)))*(?:(?=\{\{)|\Z)') + + def escape_line(line): + line = re.sub(outside_pattern, lambda m: re.escape(m.group(0)), line) + return re.sub(r'\{\{|\}\}', '', line) + + stdout = '\n'.join([escape_line(line) for line in stdout.split('\n')]) + return (stdin,stdout) + +def run(tester, io): + (input,output) = split_stdin_stdout(io) + tester.run_build_system(stdin=input, stdout=output, match=TestCmd.match_re) + +def make_tester(): + return BoostBuild.Tester(["-dmi"], pass_toolset=False, pass_d0=False, + use_test_config=False, ignore_toolset_requirements=False, match=TestCmd.match_re) + +def test_exec_run(): + t = make_tester() + t.write("test.jam", """\ + UPDATE ; + """) + + run(t, """\ +=thread-group-added,id="i1" +(gdb) +72-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +72^running +(gdb) +*stopped,reason="exited-normally" +(gdb) +73-gdb-exit +73^exit +""") + + t.cleanup() + +def test_exit_status(): + t = make_tester() + t.write("test.jam", """\ + EXIT : 1 ; + """) + run(t, """\ +=thread-group-added,id="i1" +(gdb) +72-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +72^running +(gdb) + +*stopped,reason="exited",exit-code="1" +(gdb) +73-gdb-exit +73^exit +""") + t.cleanup() + +def test_exec_step(): + t = make_tester() + t.write("test.jam", """\ + rule g ( ) + { + a = 1 ; + b = 2 ; + } + rule f ( ) + { + g ; + c = 3 ; + } + f ; + """) + run(t, """\ +=thread-group-added,id="i1" +(gdb) +-break-insert f +^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",func="f"} +(gdb) +72-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +72^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="1",disp="keep",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="8"},thread-id="1",stopped-threads="all" +(gdb) +1-exec-step +1^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="g",args=[],file="test.jam",fullname="{{.*}}test.jam",line="3"},thread-id="1" +(gdb) +2-exec-step +2^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="g",args=[],file="test.jam",fullname="{{.*}}test.jam",line="4"},thread-id="1" +(gdb) +3-exec-step +3^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="9"},thread-id="1" +(gdb) +73-gdb-exit +73^exit +""") + t.cleanup() + +def test_exec_next(): + t = make_tester() + t.write("test.jam", """\ + rule g ( ) + { + a = 1 ; + } + rule f ( ) + { + g ; + b = 2 ; + c = 3 ; + } + rule h ( ) + { + f ; + g ; + } + h ; + d = 4 ; + """) + run(t, """\ +=thread-group-added,id="i1" +(gdb) +-break-insert f +^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",func="f"} +(gdb) +72-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +72^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="1",disp="keep",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="7"},thread-id="1",stopped-threads="all" +(gdb) +1-exec-next +1^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="8"},thread-id="1" +(gdb) +2-exec-next +2^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="9"},thread-id="1" +(gdb) +3-exec-next +3^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="h",args=[],file="test.jam",fullname="{{.*}}test.jam",line="14"},thread-id="1" +(gdb) +4-exec-next +4^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="module scope",args=[],file="test.jam",fullname="{{.*}}test.jam",line="17"},thread-id="1" +(gdb) +73-gdb-exit +73^exit +""") + t.cleanup() + +def test_exec_finish(): + t = make_tester() + t.write("test.jam", """\ + rule f ( ) + { + a = 1 ; + } + rule g ( ) + { + f ; + b = 2 ; + i ; + } + rule h ( ) + { + g ; + i ; + } + rule i ( ) + { + c = 3 ; + } + h ; + d = 4 ; + """) + run(t, """\ +=thread-group-added,id="i1" +(gdb) +-break-insert f +^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",func="f"} +(gdb) +72-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +72^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="1",disp="keep",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="3"},thread-id="1",stopped-threads="all" +(gdb) +1-exec-finish +1^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="g",args=[],file="test.jam",fullname="{{.*}}test.jam",line="8"},thread-id="1" +(gdb) +2-exec-finish +2^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="h",args=[],file="test.jam",fullname="{{.*}}test.jam",line="14"},thread-id="1" +(gdb) +3-exec-finish +3^running +(gdb) +*stopped,reason="end-stepping-range",frame={func="module scope",args=[],file="test.jam",fullname="{{.*}}test.jam",line="21"},thread-id="1" +(gdb) +73-gdb-exit +73^exit +""") + t.cleanup() + + +def test_breakpoints(): + """Tests the interaction between the following commands: + break, clear, delete, disable, enable""" + t = make_tester() + t.write("test.jam", """\ + rule f ( ) + { + a = 1 ; + } + rule g ( ) + { + b = 2 ; + } + rule h ( ) + { + c = 3 ; + d = 4 ; + } + f ; + g ; + h ; + UPDATE ; + """) + run(t, """\ +=thread-group-added,id="i1" +(gdb) +-break-insert f +^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",func="f"} +(gdb) +72-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +72^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="1",disp="keep",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="3"},thread-id="1",stopped-threads="all" +(gdb) +-interpreter-exec console kill +^done +(gdb) +-break-insert g +^done,bkpt={number="2",type="breakpoint",disp="keep",enabled="y",func="g"} +(gdb) +-break-disable 1 +^done +(gdb) +73-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +73^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="2",disp="keep",frame={func="g",args=[],file="test.jam",fullname="{{.*}}test.jam",line="7"},thread-id="1",stopped-threads="all" +(gdb) +-interpreter-exec console kill +^done +(gdb) +-break-enable 1 +^done +(gdb) +74-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +74^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="1",disp="keep",frame={func="f",args=[],file="test.jam",fullname="{{.*}}test.jam",line="3"},thread-id="1",stopped-threads="all" +(gdb) +-interpreter-exec console kill +^done +(gdb) +-break-delete 1 +^done +(gdb) +75-exec-run -ftest.jam +=thread-created,id="1",group-id="i1" +75^running +(gdb) +*stopped,reason="breakpoint-hit",bkptno="2",disp="keep",frame={func="g",args=[],file="test.jam",fullname="{{.*}}test.jam",line="7"},thread-id="1",stopped-threads="all" +(gdb) +76-gdb-exit +76^exit +""") + t.cleanup() + +test_exec_run() +test_exit_status() +test_exec_step() +test_exec_next() +test_exec_finish() +test_breakpoints() diff --git a/src/boost/tools/build/test/debugger.py b/src/boost/tools/build/test/debugger.py new file mode 100644 index 00000000..24bbb9c4 --- /dev/null +++ b/src/boost/tools/build/test/debugger.py @@ -0,0 +1,674 @@ +#!/usr/bin/python + +# Copyright 2016 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test for the debugger + +import BoostBuild +import TestCmd +import re + +def split_stdin_stdout(text): + """stdin is all text after the prompt up to and including + the next newline. Everything else is stdout. stdout + may contain regular expressions enclosed in {{}}.""" + prompt = re.escape('(b2db) ') + pattern = re.compile('(?<=%s)(.*\n)' % prompt) + text = text.replace("{{bjam}}", "{{.*}}b2{{(?:\\.exe)?}}") + stdin = ''.join(re.findall(pattern, text)) + stdout = re.sub(pattern, '', text) + outside_pattern = re.compile(r'(?:\A|(?<=\}\}))(?:[^\{]|(?:\{(?!\{)))*(?:(?=\{\{)|\Z)') + + def escape_line(line): + line = re.sub(outside_pattern, lambda m: re.escape(m.group(0)), line) + return re.sub(r'\{\{|\}\}', '', line) + + stdout = '\n'.join([escape_line(line) for line in stdout.split('\n')]) + return (stdin,stdout) + +def run(tester, io): + (input,output) = split_stdin_stdout(io) + tester.run_build_system(stdin=input, stdout=output, match=TestCmd.match_re) + +def make_tester(): + return BoostBuild.Tester(["-dconsole"], pass_toolset=False, pass_d0=False, + use_test_config=False, ignore_toolset_requirements=False, match=TestCmd.match_re) + +def test_run(): + t = make_tester() + t.write("test.jam", """\ + UPDATE ; + """) + + run(t, """\ +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Child {{\d+}} exited with status 0 +(b2db) quit +""") + + t.cleanup() + +def test_exit_status(): + t = make_tester() + t.write("test.jam", """\ + EXIT : 1 ; + """) + run(t, """\ +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam + +Child {{\d+}} exited with status 1 +(b2db) quit +""") + t.cleanup() + +def test_step(): + t = make_tester() + t.write("test.jam", """\ + rule g ( ) + { + a = 1 ; + b = 2 ; + } + rule f ( ) + { + g ; + c = 3 ; + } + f ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( ) at test.jam:8 +8 g ; +(b2db) step +3 a = 1 ; +(b2db) step +4 b = 2 ; +(b2db) step +9 c = 3 ; +(b2db) quit +""") + t.cleanup() + +# Note: step doesn't need to worry about breakpoints, +# as it always stops at the next line executed. + +def test_next(): + t = make_tester() + t.write("test.jam", """\ + rule g ( ) + { + a = 1 ; + } + rule f ( ) + { + g ; + b = 2 ; + c = 3 ; + } + rule h ( ) + { + f ; + g ; + } + h ; + d = 4 ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( ) at test.jam:7 +7 g ; +(b2db) next +8 b = 2 ; +(b2db) next +9 c = 3 ; +(b2db) next +14 g ; +(b2db) next +17 d = 4 ; +(b2db) quit +""") + t.cleanup() + +def test_next_breakpoint(): + """next should stop if it encounters a breakpoint. + If the normal end point happens to be a breakpoint, + then it should be reported as normal stepping.""" + t = make_tester() + t.write("test.jam", """\ + rule f ( recurse ? ) + { + if $(recurse) { f ; } + a = 1 ; + } + rule g ( ) + { + b = 2 ; + } + f true ; + g ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) break g +Breakpoint 2 set at g +(b2db) break test.jam:4 +Breakpoint 3 set at test.jam:4 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( true ) at test.jam:3 +3 if $(recurse) { f ; } +(b2db) next +Breakpoint 1, f ( ) at test.jam:3 +3 if $(recurse) { f ; } +(b2db) next +4 a = 1 ; +(b2db) next +4 a = 1 ; +(b2db) next +11 g ; +(b2db) next +Breakpoint 2, g ( ) at test.jam:8 +8 b = 2 ; +(b2db) quit +""") + t.cleanup() + +def test_finish(): + t = make_tester() + t.write("test.jam", """\ + rule f ( ) + { + a = 1 ; + } + rule g ( ) + { + f ; + b = 2 ; + i ; + } + rule h ( ) + { + g ; + i ; + } + rule i ( ) + { + c = 3 ; + } + h ; + d = 4 ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( ) at test.jam:3 +3 a = 1 ; +(b2db) finish +8 b = 2 ; +(b2db) finish +14 i ; +(b2db) finish +21 d = 4 ; +(b2db) quit +""") + t.cleanup() + +def test_finish_breakpoints(): + """finish should stop when it reaches a breakpoint.""" + t = make_tester() + t.write("test.jam", """\ + rule f ( recurse * ) + { + if $(recurse) + { + a = [ f $(recurse[2-]) ] ; + } + } + rule g ( list * ) + { + for local v in $(list) + { + x = $(v) ; + } + } + f 1 2 ; + g 1 2 ; + """) + run(t, """\ +(b2db) break test.jam:5 +Breakpoint 1 set at test.jam:5 +(b2db) break test.jam:12 +Breakpoint 2 set at test.jam:12 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( 1 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) finish +Breakpoint 1, f ( 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) finish +5 a = [ f $(recurse[2-]) ] ; +(b2db) finish +16 g 1 2 ; +(b2db) finish +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) finish +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) quit +""") + t.cleanup() + +def test_continue_breakpoints(): + """continue should stop when it reaches a breakpoint""" + t = make_tester() + t.write("test.jam", """\ + rule f ( recurse * ) + { + if $(recurse) + { + a = [ f $(recurse[2-]) ] ; + } + } + rule g ( list * ) + { + for local v in $(list) + { + x = $(v) ; + } + } + f 1 2 ; + g 1 2 ; + """) + run(t, """\ +(b2db) break test.jam:5 +Breakpoint 1 set at test.jam:5 +(b2db) break test.jam:12 +Breakpoint 2 set at test.jam:12 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( 1 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) continue +Breakpoint 1, f ( 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) continue +Breakpoint 1, f ( 1 2 ) at test.jam:5 +5 a = [ f $(recurse[2-]) ] ; +(b2db) continue +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) continue +Breakpoint 2, g ( 1 2 ) at test.jam:12 +12 x = $(v) ; +(b2db) quit +""") + t.cleanup() + +def test_breakpoints(): + """Tests the interaction between the following commands: + break, clear, delete, disable, enable""" + t = make_tester() + t.write("test.jam", """\ + rule f ( ) + { + a = 1 ; + } + rule g ( ) + { + b = 2 ; + } + rule h ( ) + { + c = 3 ; + d = 4 ; + } + f ; + g ; + h ; + UPDATE ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( ) at test.jam:3 +3 a = 1 ; +(b2db) kill +(b2db) break g +Breakpoint 2 set at g +(b2db) disable 1 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 2, g ( ) at test.jam:7 +7 b = 2 ; +(b2db) kill +(b2db) enable 1 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( ) at test.jam:3 +3 a = 1 ; +(b2db) kill +(b2db) delete 1 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 2, g ( ) at test.jam:7 +7 b = 2 ; +(b2db) kill +(b2db) break test.jam:12 +Breakpoint 3 set at test.jam:12 +(b2db) clear g +Deleted breakpoint 2 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 3, h ( ) at test.jam:12 +12 d = 4 ; +(b2db) kill +(b2db) clear test.jam:12 +Deleted breakpoint 3 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Child {{\d+}} exited with status 0 +(b2db) quit +""") + t.cleanup() + +def test_breakpoints_running(): + """Tests that breakpoints can be added and modified + while the program is running.""" + t = make_tester() + t.write("test.jam", """\ + rule f ( ) + { + a = 1 ; + } + rule g ( ) + { + b = 2 ; + } + rule h ( ) + { + c = 3 ; + d = 4 ; + } + f ; + g ; + h ; + UPDATE ; + """) + run(t, """\ +(b2db) break test.jam:14 +Breakpoint 1 set at test.jam:14 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:14 +14 f ; +(b2db) break f +Breakpoint 2 set at f +(b2db) continue +Breakpoint 2, f ( ) at test.jam:3 +3 a = 1 ; +(b2db) kill +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:14 +14 f ; +(b2db) break g +Breakpoint 3 set at g +(b2db) disable 2 +(b2db) continue +Breakpoint 3, g ( ) at test.jam:7 +7 b = 2 ; +(b2db) kill +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:14 +14 f ; +(b2db) enable 2 +(b2db) continue +Breakpoint 2, f ( ) at test.jam:3 +3 a = 1 ; +(b2db) kill +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:14 +14 f ; +(b2db) delete 2 +(b2db) continue +Breakpoint 3, g ( ) at test.jam:7 +7 b = 2 ; +(b2db) kill +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:14 +14 f ; +(b2db) break test.jam:12 +Breakpoint 4 set at test.jam:12 +(b2db) clear g +Deleted breakpoint 3 +(b2db) continue +Breakpoint 4, h ( ) at test.jam:12 +12 d = 4 ; +(b2db) kill +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:14 +14 f ; +(b2db) clear test.jam:12 +Deleted breakpoint 4 +(b2db) continue +Child {{\d+}} exited with status 0 +(b2db) quit +""") + t.cleanup() + +def test_backtrace(): + t = make_tester() + t.write("test.jam", """\ + rule f ( x * : y * : z * ) + { + return $(x) ; + } + rule g ( x * : y * : z * ) + { + return [ f $(x) : $(y) : $(z) ] ; + } + g 1 : 2 : 3 ; + """) + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( 1 : 2 : 3 ) at test.jam:3 +3 return $(x) ; +(b2db) backtrace +#0 in f ( 1 : 2 : 3 ) at test.jam:3 +#1 in g ( 1 : 2 : 3 ) at test.jam:7 +#2 in module scope at test.jam:9 +(b2db) quit +""") + t.cleanup() + +def test_print(): + t = make_tester() + t.write("test.jam", """\ + rule f ( args * ) + { + return $(args) ; + } + f x ; + f x y ; + """) + + run(t, """\ +(b2db) break f +Breakpoint 1 set at f +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, f ( x ) at test.jam:3 +3 return $(args) ; +(b2db) print $(args) +x +(b2db) continue +Breakpoint 1, f ( x y ) at test.jam:3 +3 return $(args) ; +(b2db) print $(args) +x y +(b2db) disable 1 +(b2db) print [ f z ] +z +(b2db) quit +""") + + t.cleanup() + +def test_run_running(): + t = make_tester() + t.write("test.jam", """\ + UPDATE ; + """) + + run(t, """\ +(b2db) break test.jam:1 +Breakpoint 1 set at test.jam:1 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:1 +1 UPDATE ; +(b2db) run -ftest.jam +Child {{\d+}} exited with status 0 +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:1 +1 UPDATE ; +(b2db) quit +""") + + t.cleanup() + +def test_error_not_running(): + t = make_tester() + run(t, """\ +(b2db) continue +The program is not being run. +(b2db) step +The program is not being run. +(b2db) next +The program is not being run. +(b2db) finish +The program is not being run. +(b2db) kill +The program is not being run. +(b2db) backtrace +The program is not being run. +(b2db) print 1 +The program is not being run. +(b2db) quit +""") + + t.cleanup() + +def test_bad_arguments(): + t = make_tester() + t.write("test.jam", """\ + UPDATE ; + """) + + run(t, """\ +(b2db) break test.jam:1 +Breakpoint 1 set at test.jam:1 +(b2db) run -ftest.jam +Starting program: {{bjam}} -ftest.jam +Breakpoint 1, module scope at test.jam:1 +1 UPDATE ; +(b2db) continue 1 +Too many arguments to continue. +(b2db) step 1 +Too many arguments to step. +(b2db) next 1 +Too many arguments to next. +(b2db) finish 1 +Too many arguments to finish. +(b2db) break +Missing argument to break. +(b2db) break x y +Too many arguments to break. +(b2db) disable +Missing argument to disable. +(b2db) disable 1 2 +Too many arguments to disable. +(b2db) disable x +Invalid breakpoint number x. +(b2db) disable 2 +Unknown breakpoint 2. +(b2db) enable +Missing argument to enable. +(b2db) enable 1 2 +Too many arguments to enable. +(b2db) enable x +Invalid breakpoint number x. +(b2db) enable 2 +Unknown breakpoint 2. +(b2db) delete +Missing argument to delete. +(b2db) delete 1 2 +Too many arguments to delete. +(b2db) delete x +Invalid breakpoint number x. +(b2db) delete 2 +Unknown breakpoint 2. +(b2db) clear +Missing argument to clear. +(b2db) clear test.jam:1 test.jam:1 +Too many arguments to clear. +(b2db) clear test.jam:2 +No breakpoint at test.jam:2. +(b2db) quit +""") + + t.cleanup() + +def test_unknown_command(): + t = make_tester() + run(t, """\ +(b2db) xyzzy +Unknown command: xyzzy +(b2db) gnusto rezrov +Unknown command: gnusto +(b2db) quit +""") + + t.cleanup() + +test_run() +test_exit_status() +test_step() +test_next() +test_next_breakpoint() +test_finish() +test_finish_breakpoints() +test_continue_breakpoints() +test_breakpoints() +test_breakpoints_running() +test_backtrace() +test_print() +test_run_running() +test_error_not_running() +test_bad_arguments() +test_unknown_command() diff --git a/src/boost/tools/build/test/default_build.py b/src/boost/tools/build/test/default_build.py new file mode 100644 index 00000000..6206507f --- /dev/null +++ b/src/boost/tools/build/test/default_build.py @@ -0,0 +1,80 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that default build clause actually has any effect. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "") +t.write("jamfile.jam", "exe a : a.cpp : : debug release ;") +t.write("a.cpp", "int main() {}\n") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") +t.expect_addition("bin/$toolset/release*/a.exe") + +# Check that explictly-specified build variant suppresses default-build. +t.rm("bin") +t.run_build_system(["release"]) +t.expect_addition(BoostBuild.List("bin/$toolset/release*/") * "a.exe a.obj") +t.expect_nothing_more() + +# Now check that we can specify explicit build request and default-build will be +# combined with it. +t.run_build_system(["optimization=space"]) +t.expect_addition("bin/$toolset/debug/optimization-space*/a.exe") +t.expect_addition("bin/$toolset/release/optimization-space*/a.exe") + +# Test that default-build must be identical in all alternatives. Error case. +t.write("jamfile.jam", """\ +exe a : a.cpp : : debug ; +exe a : b.cpp : : ; +""") +t.run_build_system(["-n", "--no-error-backtrace"], status=1) +t.fail_test(t.stdout().find("default build must be identical in all alternatives") == -1) + +# Test that default-build must be identical in all alternatives. No Error case, +# empty default build. +t.write("jamfile.jam", """\ +exe a : a.cpp : <variant>debug ; +exe a : b.cpp : <variant>release ; +""") +t.run_build_system(["-n", "--no-error-backtrace"], status=0) + +# Now try a harder example: default build which contains <define> should cause +# <define> to be present when "b" is compiled. This happens only if +# "build-project b" is placed first. +t.write("jamfile.jam", """\ +project : default-build <define>FOO ; +build-project a ; +build-project b ; +""") + +t.write("a/jamfile.jam", "exe a : a.cpp ../b//b ;") +t.write("a/a.cpp", """\ +#ifdef _WIN32 +__declspec(dllimport) +#endif +void foo(); +int main() { foo(); } +""") + +t.write("b/jamfile.jam", "lib b : b.cpp ;") +t.write("b/b.cpp", """\ +#ifdef FOO +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() {} +#endif +""") + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/default_features.py b/src/boost/tools/build/test/default_features.py new file mode 100644 index 00000000..1d6d72a6 --- /dev/null +++ b/src/boost/tools/build/test/default_features.py @@ -0,0 +1,50 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that features with default values are always present in build properties +# of any target. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# Declare *non-propagated* feature foo. +t.write("jamroot.jam", """ +import feature : feature ; +feature foo : on off ; +""") + +# Note that '<foo>on' will not be propagated to 'd/l'. +t.write("jamfile.jam", """ +exe hello : hello.cpp d//l ; +""") + +t.write("hello.cpp", """ +#ifdef _WIN32 +__declspec(dllimport) +#endif +void foo(); +int main() { foo(); } +""") + +t.write("d/jamfile.jam", """ +lib l : l.cpp : <foo>on:<define>FOO ; +""") + +t.write("d/l.cpp", """ +#ifdef _WIN32 +__declspec(dllexport) +#endif +#ifdef FOO +void foo() {} +#endif +""") + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/default_toolset.py b/src/boost/tools/build/test/default_toolset.py new file mode 100755 index 00000000..682e7fcc --- /dev/null +++ b/src/boost/tools/build/test/default_toolset.py @@ -0,0 +1,215 @@ +#!/usr/bin/python + +# Copyright 2008 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that the expected default toolset is used when no toolset is explicitly +# specified on the command line or used from code via the using rule. Test that +# the default toolset is correctly used just like any other explicitly used +# toolset (e.g. toolset prerequisites, properties conditioned on toolset +# related features, etc.). +# +# Note that we need to ignore regular site/user/test configuration files to +# avoid them marking any toolsets not under our control as used. + +import BoostBuild + + +# Line displayed by Boost Build when using the default toolset. +configuring_default_toolset_message = \ + 'warning: Configuring default toolset "%s".' + + +############################################################################### +# +# test_conditions_on_default_toolset() +# ------------------------------------ +# +############################################################################### + +def test_conditions_on_default_toolset(): + """Test that toolset and toolset subfeature conditioned properties get + applied correctly when the toolset is selected by default. Implicitly tests + that we can use the set-default-toolset rule to set the default toolset to + be used by Boost Build. + """ + + t = BoostBuild.Tester("--user-config= --ignore-site-config", + pass_toolset=False, use_test_config=False) + + toolset_name = "myCustomTestToolset" + toolset_version = "v" + toolset_version_unused = "v_unused" + message_loaded = "Toolset '%s' loaded." % toolset_name + message_initialized = "Toolset '%s' initialized." % toolset_name ; + + # Custom toolset. + t.write(toolset_name + ".jam", """ +import feature ; +ECHO "%(message_loaded)s" ; +feature.extend toolset : %(toolset_name)s ; +feature.subfeature toolset %(toolset_name)s : version : %(toolset_version)s %(toolset_version_unused)s ; +rule init ( version ) { ECHO "%(message_initialized)s" ; } +""" % {'message_loaded' : message_loaded , + 'message_initialized' : message_initialized, + 'toolset_name' : toolset_name , + 'toolset_version' : toolset_version , + 'toolset_version_unused': toolset_version_unused}) + + # Main Boost Build project script. + t.write("jamroot.jam", """ +import build-system ; +import errors ; +import feature ; +import notfile ; + +build-system.set-default-toolset %(toolset_name)s : %(toolset_version)s ; + +feature.feature description : : free incidental ; + +# We use a rule instead of an action to avoid problems with action output not +# getting piped to stdout by the testing system. +rule buildRule ( names : targets ? : properties * ) +{ + local descriptions = [ feature.get-values description : $(properties) ] ; + ECHO "descriptions:" /$(descriptions)/ ; + local toolset = [ feature.get-values toolset : $(properties) ] ; + ECHO "toolset:" /$(toolset)/ ; + local toolset-version = [ feature.get-values "toolset-$(toolset):version" : $(properties) ] ; + ECHO "toolset-version:" /$(toolset-version)/ ; +} + +notfile testTarget + : @buildRule + : + : + <description>stand-alone + <toolset>%(toolset_name)s:<description>toolset + <toolset>%(toolset_name)s-%(toolset_version)s:<description>toolset-version + <toolset>%(toolset_name)s-%(toolset_version_unused)s:<description>toolset-version-unused ; +""" % {'toolset_name' : toolset_name , + 'toolset_version' : toolset_version, + 'toolset_version_unused': toolset_version_unused}) + + t.run_build_system() + t.expect_output_lines(configuring_default_toolset_message % toolset_name) + t.expect_output_lines(message_loaded) + t.expect_output_lines(message_initialized) + t.expect_output_lines("descriptions: /stand-alone/ /toolset/ " + "/toolset-version/") + t.expect_output_lines("toolset: /%s/" % toolset_name) + t.expect_output_lines("toolset-version: /%s/" % toolset_version) + + t.cleanup() + + +############################################################################### +# +# test_default_toolset_on_os() +# ---------------------------- +# +############################################################################### + +def test_default_toolset_on_os( os, expected_toolset ): + """Test that the given toolset is used as the default toolset on the given + os. Uses hardcoded knowledge of how Boost Build decides on which host OS it + is currently running. Note that we must not do much after tricking Boost + Build into believing it has a specific host OS as this might mess up other + important internal Boost Build state. + """ + + t = BoostBuild.Tester("--user-config= --ignore-site-config", + pass_toolset=False, use_test_config=False) + + t.write("jamroot.jam", "modules.poke os : .name : %s ;" % os) + + # We need to tell the test system to ignore stderr output as attempting to + # load missing toolsets might cause random failures with which we are not + # concerned in this test. + t.run_build_system(stderr=None) + t.expect_output_lines(configuring_default_toolset_message % + expected_toolset) + + t.cleanup() + + +############################################################################### +# +# test_default_toolset_requirements() +# ----------------------------------- +# +############################################################################### + +def test_default_toolset_requirements(): + """Test that default toolset's requirements get applied correctly. + """ + + t = BoostBuild.Tester("--user-config= --ignore-site-config", + pass_toolset=False, use_test_config=False, + ignore_toolset_requirements=False) + + toolset_name = "customTestToolsetWithRequirements" + + # Custom toolset. + t.write(toolset_name + ".jam", """ +import feature ; +import toolset ; +feature.extend toolset : %(toolset_name)s ; +toolset.add-requirements <description>toolset-requirement ; +rule init ( ) { } +""" % {'toolset_name': toolset_name}) + + # Main Boost Build project script. + t.write("jamroot.jam", """ +import build-system ; +import errors ; +import feature ; +import notfile ; + +build-system.set-default-toolset %(toolset_name)s ; + +feature.feature description : : free incidental ; + +# We use a rule instead of an action to avoid problems with action output not +# getting piped to stdout by the testing system. +rule buildRule ( names : targets ? : properties * ) +{ + local descriptions = [ feature.get-values description : $(properties) ] ; + ECHO "descriptions:" /$(descriptions)/ ; + local toolset = [ feature.get-values toolset : $(properties) ] ; + ECHO "toolset:" /$(toolset)/ ; +} + +notfile testTarget + : @buildRule + : + : + <description>target-requirement + <description>toolset-requirement:<description>conditioned-requirement + <description>unrelated-condition:<description>unrelated-description ; +""" % {'toolset_name': toolset_name}) + + t.run_build_system() + t.expect_output_lines(configuring_default_toolset_message % toolset_name) + t.expect_output_lines("descriptions: /conditioned-requirement/ " + "/target-requirement/ /toolset-requirement/") + t.expect_output_lines("toolset: /%s/" % toolset_name) + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +test_default_toolset_on_os("NT" , "msvc") +test_default_toolset_on_os("LINUX" , "gcc" ) +test_default_toolset_on_os("CYGWIN" , "gcc" ) +test_default_toolset_on_os("SomeOtherOS", "gcc" ) +test_default_toolset_requirements() +test_conditions_on_default_toolset() diff --git a/src/boost/tools/build/test/dependency_property.py b/src/boost/tools/build/test/dependency_property.py new file mode 100644 index 00000000..b6753925 --- /dev/null +++ b/src/boost/tools/build/test/dependency_property.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Regression test: virtual targets with different dependency properties were +# considered different by 'virtual-target.register', but the code which +# determined the actual target paths ignored dependency properties so both +# targets ended up being in the same location. +# +# This test has flip-flopped several times between passing and failing. +# Currently, the library is only considered relevant for linking and thus +# does not cause a conflict. SJW 20180115 + +import BoostBuild + + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """\ +lib foo : foo.cpp ; +exe hello : hello.cpp ; +exe hello2 : hello.cpp : <library>foo ; +""") + +t.write("hello.cpp", "int main() {}\n") + +t.write("foo.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() {} +""") + +t.run_build_system(["--no-error-backtrace"], status=0) + +t.cleanup() diff --git a/src/boost/tools/build/test/dependency_test.py b/src/boost/tools/build/test/dependency_test.py new file mode 100644 index 00000000..85295577 --- /dev/null +++ b/src/boost/tools/build/test/dependency_test.py @@ -0,0 +1,239 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2005, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + + +def test_basic(): + t = BoostBuild.Tester(["-d3", "-d+12"], use_test_config=False) + + t.write("a.cpp", """ +#include <a.h> +# include "a.h" +#include <x.h> +int main() {} +""") + t.write("a.h", "\n") + t.write("a_c.c", """\ +#include <a.h> +# include "a.h" +#include <x.h> +""") + t.write("b.cpp", """\ +#include "a.h" +int main() {} +""") + t.write("b.h", "\n") + t.write("c.cpp", """\ +#include "x.h" +int main() {} +""") + t.write("e.cpp", """\ +#include "x.h" +int main() {} +""") + t.write("x.foo", "") + t.write("y.foo", "") + + t.write("src1/a.h", '#include "b.h"\n') + t.write("src1/b.h", '#include "c.h"\n') + t.write("src1/c.h", "\n") + t.write("src1/z.h", """\ +extern int dummy_variable_suppressing_empty_file_warning_on_hp_cxx_compiler; +""") + + t.write("src2/b.h", "\n") + + t.write("jamroot.jam", """\ +import foo ; +import types/cpp ; +import types/exe ; + +project test : requirements <include>src1 ; + +exe a : x.foo a.cpp a_c.c ; +exe b : b.cpp ; + +# Because of <define>FOO, c.cpp will be compiled to a different directory than +# everything for main target "a". Therefore, without <implicit-dependency>, C +# preprocessor processing that module will not find "x.h", which is part of +# "a"'s dependency graph. +# +# -------------------------- +# More detailed explanation: +# -------------------------- +# c.cpp includes x.h which does not exist on the current include path so Boost +# Jam will try to match it to existing Jam targets to cover cases as this one +# where the file is generated by the same build. +# +# However, as x.h is not part of "c" metatarget's dependency graph, Boost +# Build will not actualize its target by default, i.e. create its Jam target. +# +# To get the Jam target created in time, we use the <implicit-dependency> +# feature. This tells Boost Build that it needs to actualize the dependency +# graph for metatarget "a", even though that metatarget has not been directly +# mentioned and is not a dependency for any of the metatargets mentioned in the +# current build request. +# +# Note that Boost Build does not automatically add a dependency between the +# Jam targets in question so, if Boost Jam does not add a dependency on a target +# from that other dependency graph (x.h in our case), i.e. if c.cpp does not +# actually include x.h, us actualizing it will have no effect in the end as +# Boost Jam will not have a reason to actually build those targets in spite of +# knowing about them. +exe c : c.cpp : <define>FOO <implicit-dependency>a ; +""") + + t.write("foo.jam", """\ +import generators ; +import modules ; +import os ; +import print ; +import type ; +import types/cpp ; + +type.register FOO : foo ; + +generators.register-standard foo.foo : FOO : CPP H ; + +nl = " +" ; + +rule foo ( targets * : sources * : properties * ) +{ + # On NT, you need an exported symbol in order to have an import library + # generated. We will not really use the symbol defined here, just force the + # import library creation. + if ( [ os.name ] = NT || [ modules.peek : OS ] in CYGWIN ) && + <main-target-type>LIB in $(properties) + { + .decl = "void __declspec(dllexport) foo() {}" ; + } + print.output $(<[1]) ; + print.text $(.decl:E="//")$(nl) ; + print.output $(<[2]) ; + print.text "#include <z.h>"$(nl) ; +} +""") + + t.write("foo.py", +r"""import bjam +import b2.build.type as type +import b2.build.generators as generators + +from b2.manager import get_manager + +type.register("FOO", ["foo"]) +generators.register_standard("foo.foo", ["FOO"], ["CPP", "H"]) + +def prepare_foo(targets, sources, properties): + if properties.get('os') in ['windows', 'cygwin']: + bjam.call('set-target-variable', targets, "DECL", + "void __declspec(dllexport) foo() {}") + +get_manager().engine().register_action("foo.foo", + "echo -e $(DECL:E=//)\\n > $(<[1])\n" + "echo -e "#include <z.h>\\n" > $(<[2])\n", function=prepare_foo) +""") + + # Check that main target 'c' was able to find 'x.h' from 'a's dependency + # graph. + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/c.exe") + + # Check handling of first level includes. + + # Both 'a' and 'b' include "a.h" and should be updated. + t.touch("a.h") + t.run_build_system() + + t.expect_touch("bin/$toolset/debug*/a.exe") + t.expect_touch("bin/$toolset/debug*/a.obj") + t.expect_touch("bin/$toolset/debug*/a_c.obj") + t.expect_touch("bin/$toolset/debug*/b.exe") + t.expect_touch("bin/$toolset/debug*/b.obj") + t.expect_nothing_more() + + # Only source files using include <a.h> should be compiled. + t.touch("src1/a.h") + t.run_build_system() + + t.expect_touch("bin/$toolset/debug*/a.exe") + t.expect_touch("bin/$toolset/debug*/a.obj") + t.expect_touch("bin/$toolset/debug*/a_c.obj") + t.expect_nothing_more() + + # "src/a.h" includes "b.h" (in the same dir). + t.touch("src1/b.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/a.exe") + t.expect_touch("bin/$toolset/debug*/a.obj") + t.expect_touch("bin/$toolset/debug*/a_c.obj") + t.expect_nothing_more() + + # Included by "src/b.h". We had a bug: file included using double quotes + # (e.g. "b.h") was not scanned at all in this case. + t.touch("src1/c.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/a.exe") + + t.touch("b.h") + t.run_build_system() + t.expect_nothing_more() + + # Test dependency on a generated header. + # + # TODO: we have also to check that generated header is found correctly if + # it is different for different subvariants. Lacking any toolset support, + # this check will be implemented later. + t.touch("x.foo") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/a.obj") + t.expect_touch("bin/$toolset/debug*/a_c.obj") + + # Check that generated headers are scanned for dependencies as well. + t.touch("src1/z.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/a.obj") + t.expect_touch("bin/$toolset/debug*/a_c.obj") + + t.cleanup() + + +def test_scanned_includes_with_absolute_paths(): + """ + Regression test: on Windows, <includes> with absolute paths were not + considered when scanning dependencies. + + """ + t = BoostBuild.Tester(["-d3", "-d+12"]) + + t.write("jamroot.jam", """\ +path-constant TOP : . ; +exe app : main.cpp : <include>$(TOP)/include ; +"""); + + t.write("main.cpp", """\ +#include <dir/header.h> +int main() {} +""") + + t.write("include/dir/header.h", "\n") + + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/main.obj") + + t.touch("include/dir/header.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/main.obj") + + t.cleanup() + + +test_basic() +test_scanned_includes_with_absolute_paths() diff --git a/src/boost/tools/build/test/disambiguation.py b/src/boost/tools/build/test/disambiguation.py new file mode 100644 index 00000000..9544aa0f --- /dev/null +++ b/src/boost/tools/build/test/disambiguation.py @@ -0,0 +1,32 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that it is possible to add a suffix to a main target name to disambiguate +# that main target from another, and that this does not affect the names of the +# generated targets. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +exe hello.exe : hello.obj ; +obj hello.obj : hello.cpp : <variant>debug ; +obj hello.obj2 : hello.cpp : <variant>release ; +""") + +t.write("hello.cpp", """ +int main() {} +""") + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/hello.exe") +t.expect_addition("bin/$toolset/debug*/hello.obj") +t.expect_addition("bin/$toolset/release*/hello.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/dll_path.py b/src/boost/tools/build/test/dll_path.py new file mode 100644 index 00000000..f7331cdf --- /dev/null +++ b/src/boost/tools/build/test/dll_path.py @@ -0,0 +1,163 @@ +#!/usr/bin/python + +# Copyright (C) 2003. Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that the <dll-path> property is correctly set when using +# <hardcode-dll-paths>true. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# The point of this test is to have exe "main" which uses library "b", which +# uses library "a". When "main" is built with <hardcode-dll-paths>true, paths +# to both libraries should be present as values of <dll-path> feature. We +# create a special target type which reports <dll-path> values on its sources +# and compare the list of found values with out expectations. + +t.write("jamroot.jam", "using dll_paths ;") +t.write("jamfile.jam", """\ +exe main : main.cpp b//b ; +explicit main ; +path-list mp : main ; +""") + +t.write("main.cpp", "int main() {}\n") +t.write("dll_paths.jam", """\ +import "class" : new ; +import feature ; +import generators ; +import print ; +import sequence ; +import type ; + +rule init ( ) +{ + type.register PATH_LIST : pathlist ; + + class dll-paths-list-generator : generator + { + rule __init__ ( ) + { + generator.__init__ dll_paths.list : EXE : PATH_LIST ; + } + + rule generated-targets ( sources + : property-set : project name ? ) + { + local dll-paths ; + for local s in $(sources) + { + local a = [ $(s).action ] ; + if $(a) + { + local p = [ $(a).properties ] ; + dll-paths += [ $(p).get <dll-path> ] ; + } + } + return [ generator.generated-targets $(sources) : + [ $(property-set).add-raw $(dll-paths:G=<dll-path>) ] : + $(project) $(name) ] ; + } + } + generators.register [ new dll-paths-list-generator ] ; +} + +rule list ( target : sources * : properties * ) +{ + local paths = [ feature.get-values <dll-path> : $(properties) ] ; + paths = [ sequence.insertion-sort $(paths) ] ; + print.output $(target) ; + print.text $(paths) ; +} +""") + +t.write("dll_paths.py", """\ +import bjam + +import b2.build.type as type +import b2.build.generators as generators + +from b2.manager import get_manager + +def init(): + type.register("PATH_LIST", ["pathlist"]) + + class DllPathsListGenerator(generators.Generator): + + def __init__(self): + generators.Generator.__init__(self, "dll_paths.list", False, + ["EXE"], ["PATH_LIST"]) + + def generated_targets(self, sources, ps, project, name): + dll_paths = [] + for s in sources: + a = s.action() + if a: + p = a.properties() + dll_paths += p.get('dll-path') + dll_paths.sort() + return generators.Generator.generated_targets(self, sources, + ps.add_raw(["<dll-path>" + p for p in dll_paths]), project, + name) + + generators.register(DllPathsListGenerator()) + +command = \"\"\" +echo $(PATHS) > $(<[1]) +\"\"\" +def function(target, sources, ps): + bjam.call('set-target-variable', target, "PATHS", ps.get('dll-path')) + +get_manager().engine().register_action("dll_paths.list", command, + function=function) +""") + +t.write("a/jamfile.jam", "lib a : a.cpp ;") +t.write("a/a.cpp", """\ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +foo() {} +""") + +t.write("b/jamfile.jam", "lib b : b.cpp ../a//a ;") +t.write("b/b.cpp", """\ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +bar() {} +""") + +t.run_build_system(["hardcode-dll-paths=true"]) + +t.expect_addition("bin/$toolset/debug*/mp.pathlist") + +es1 = t.adjust_name("a/bin/$toolset/debug*") +es2 = t.adjust_name("b/bin/$toolset/debug*") + +t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es1) +t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es2) + +t.rm("bin/$toolset/debug*/mp.pathlist") + +# Now run the same checks with pre-built libraries +adll = t.glob_file("a/bin/$toolset/debug*/a.dll") +bdll = t.glob_file("b/bin/$toolset/debug*/b.dll") +t.write("b/jamfile.jam", """ +local bdll = %s ; +# Make sure that it is found even with multiple source-locations +project : source-location c $(bdll:D) ; +lib b : ../a//a : <file>$(bdll:D=) ; +""" % bdll.replace("\\", "\\\\")) +t.run_build_system(["hardcode-dll-paths=true"]) +t.expect_addition("bin/$toolset/debug*/mp.pathlist") + +t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es1) +t.expect_content_lines("bin/$toolset/debug*/mp.pathlist", "*" + es2) + +t.cleanup() diff --git a/src/boost/tools/build/test/double_loading.py b/src/boost/tools/build/test/double_loading.py new file mode 100644 index 00000000..c708b00f --- /dev/null +++ b/src/boost/tools/build/test/double_loading.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester() + +# Regression test for double loading of the same Jamfile. +t.write("jamroot.jam", "") +t.write("jamfile.jam", "build-project subdir ;") +t.write("subdir/jamfile.jam", 'ECHO "Loaded subdir" ;') + +t.run_build_system(subdir="subdir") +t.expect_output_lines("Loaded subdir") + + +# Regression test for a more contrived case. The top-level Jamfile refers to +# subdir via use-project, while subdir's Jamfile is being loaded. The +# motivation why use-project referring to subprojects is useful can be found +# at: http://article.gmane.org/gmane.comp.lib.boost.build/3906 +t.write("jamroot.jam", "") +t.write("jamfile.jam", "use-project /subdir : subdir ;") +t.write("subdir/jamfile.jam", "project subdir ;") + +t.run_build_system(subdir="subdir"); + +t.cleanup() diff --git a/src/boost/tools/build/test/duplicate.py b/src/boost/tools/build/test/duplicate.py new file mode 100644 index 00000000..1d0d5f7f --- /dev/null +++ b/src/boost/tools/build/test/duplicate.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This test tries to stage the same file to the same location by *two* different +# stage rules, in two different projects. This is not exactly good thing to do, +# but still, V2 should handle this. We had two bugs: +# - since the file is referred from two projects, we created to different +# virtual targets +# - we also failed to figure out that the two target corresponding to the copied +# files (created in two projects) are actually equivalent. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("a.cpp", """ +""") + +t.write("jamroot.jam", """ +build-project a ; +build-project b ; +""") + +t.write("a/jamfile.jam", """ +stage bin : ../a.cpp : <location>../dist ; +""") + +t.write("b/jamfile.jam", """ +stage bin : ../a.cpp : <location>../dist ; +""") + +t.run_build_system() +t.expect_addition("dist/a.cpp") + +t.cleanup() diff --git a/src/boost/tools/build/test/example_customization.py b/src/boost/tools/build/test/example_customization.py new file mode 100644 index 00000000..462de562 --- /dev/null +++ b/src/boost/tools/build/test/example_customization.py @@ -0,0 +1,21 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'customization' example. + +import BoostBuild + +t = BoostBuild.Tester() + +t.set_tree("../example/customization") + +t.run_build_system() + +t.expect_addition(["bin/$toolset/debug*/codegen.exe", + "bin/$toolset/debug*/usage.cpp"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/example_gettext.py b/src/boost/tools/build/test/example_gettext.py new file mode 100644 index 00000000..aa836130 --- /dev/null +++ b/src/boost/tools/build/test/example_gettext.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'gettext' example. + +import BoostBuild +import os +import string + +t = BoostBuild.Tester() + +t.set_tree("../example/gettext") + +t.run_build_system(stderr=None) + +t.expect_addition(["bin/$toolset/debug*/main.exe", + "bin/$toolset/debug*/russian.mo"]) + +file = t.adjust_names(["bin/$toolset/debug*/main.exe"])[0] + +input_fd = os.popen(file) +input = input_fd.read(); + +t.fail_test(input.find("international hello") != 0) + +t.cleanup() diff --git a/src/boost/tools/build/test/example_libraries.py b/src/boost/tools/build/test/example_libraries.py new file mode 100644 index 00000000..60607b14 --- /dev/null +++ b/src/boost/tools/build/test/example_libraries.py @@ -0,0 +1,21 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'libraries' example. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.set_tree("../example/libraries") + +t.run_build_system() + +t.expect_addition(["app/bin/$toolset/debug*/app.exe", + "util/foo/bin/$toolset/debug*/bar.dll"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/example_make.py b/src/boost/tools/build/test/example_make.py new file mode 100644 index 00000000..d72423cb --- /dev/null +++ b/src/boost/tools/build/test/example_make.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'make' example. + +import BoostBuild +import sys + +t = BoostBuild.Tester(['example.python.interpreter=%s' % sys.executable]) +t.set_tree("../example/make") +t.run_build_system() +t.expect_addition(["bin/main.cpp"]) +t.cleanup() diff --git a/src/boost/tools/build/test/example_qt4.py b/src/boost/tools/build/test/example_qt4.py new file mode 100644 index 00000000..936e6f71 --- /dev/null +++ b/src/boost/tools/build/test/example_qt4.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'qt4' examples. + +import BoostBuild + +t = BoostBuild.Tester() + +t.set_tree("../example/qt/qt4/hello") +t.run_build_system() +t.expect_addition(["bin/$toolset/debug*/threading-multi/arrow"]) + +t.set_tree("../example/qt/qt4/moccable-cpp") +t.run_build_system() +t.expect_addition(["bin/$toolset/debug*/threading-multi/main"]) + +t.set_tree("../example/qt/qt4/uic") +t.run_build_system() +t.expect_addition(["bin/$toolset/debug*/threading-multi/hello"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/exit_status.py b/src/boost/tools/build/test/exit_status.py new file mode 100755 index 00000000..11c4abf7 --- /dev/null +++ b/src/boost/tools/build/test/exit_status.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2010. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that build failure results in non-zero exit status + +import BoostBuild + +# Create a temporary working directory. +t = BoostBuild.Tester() + +# Create the needed files. +t.write("jamroot.jam", """ +exe hello : hello.cpp ; +""") + +t.write("hello.cpp", """ +int main() { +""") + +t.run_build_system(status=1) + +t.cleanup() diff --git a/src/boost/tools/build/test/expansion.py b/src/boost/tools/build/test/expansion.py new file mode 100644 index 00000000..9042407f --- /dev/null +++ b/src/boost/tools/build/test/expansion.py @@ -0,0 +1,140 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +import BoostBuild + +t = BoostBuild.Tester(arguments=["--config="], pass_toolset=0) + +t.write("source.input", "") + +t.write("test-properties.jam", """ +import feature : feature ; +import generators ; +import toolset ; +import type ; + +# We're not using the toolset at all, and we want to +# suppress toolset initialization to avoid surprises. +feature.extend toolset : null ; + +type.register CHECK : check ; +type.register INPUT : input ; +feature expected-define : : free ; +feature unexpected-define : : free ; +toolset.flags test-properties DEFINES : <define> ; +toolset.flags test-properties EXPECTED : <expected-define> ; +toolset.flags test-properties UNEXPECTED : <unexpected-define> ; +generators.register-standard test-properties.check : INPUT : CHECK ; +rule check ( target : source : properties * ) +{ + local defines = [ on $(target) return $(DEFINES) ] ; + for local macro in [ on $(target) return $(EXPECTED) ] + { + if ! ( $(macro) in $(defines) ) + { + EXIT expected $(macro) for $(target) in $(properties) : 1 ; + } + } + for local macro in [ on $(target) return $(UNEXPECTED) ] + { + if $(macro) in $(defines) + { + EXIT unexpected $(macro) for $(target) in $(properties) : 1 ; + } + } +} +actions check +{ + echo okay > $(<) +} +""") + +t.write("jamfile.jam", """ +import test-properties ; +# See if default value of composite feature 'cf' will be expanded to +# <define>CF_IS_OFF. +check a : source.input : <expected-define>CF_IS_OFF ; + +# See if subfeature in requirements in expanded. +check b : source.input : <cf>on-1 + <expected-define>CF_1 <unexpected-define>CF_IS_OFF ; + +# See if conditional requirements are recursively expanded. +check c : source.input : <toolset>null:<variant>release + <variant>release:<define>FOO <expected-define>FOO + ; + +# Composites specified in the default build should not +# be expanded if they are overridden in the the requirements. +check d : source.input : <cf>on <unexpected-define>CF_IS_OFF : <cf>off ; + +# Overriding a feature should clear subfeatures and +# apply default values of subfeatures. +check e : source.input : <cf>always + <unexpected-define>CF_IS_OFF <expected-define>CF_2 <unexpected-define>CF_1 + : <cf>on-1 ; + +# Subfeatures should not be changed if the parent feature doesn't change +check f : source.input : <cf>on <expected-define>CF_1 : <cf>on-1 ; + +# If a subfeature is not specific to the value of the parent feature, +# then changing the parent value should not clear the subfeature. +check g : source.input : <fopt>off <expected-define>FOPT_2 : <fopt>on-2 ; + +# If the default value of a composite feature adds an optional +# feature which has a subfeature with a default, then that +# default should be added. +check h : source.input : <expected-define>CX_2 ; + +# If the default value of a feature is used, then the +# default value of its subfeatures should also be used. +check i : source.input : <expected-define>SF_1 ; + +# Subfeatures should be expanded when listed in a +# target reference. +check j-impl : source.input : <expected-define>CF_1 ; +explicit j-impl ; +alias j : j-impl/<cf>on-1 ; +""") + +t.write("jamroot.jam", """ +import feature ; +feature.feature cf : off on always : composite incidental ; +feature.compose <cf>off : <define>CF_IS_OFF ; +feature.subfeature cf on : version : 1 2 : composite optional incidental ; +feature.compose <cf-on:version>1 : <define>CF_1 ; +feature.subfeature cf always : version : 1 2 : composite incidental ; +feature.compose <cf-always:version>1 : <define>CF_2 ; +feature.feature fopt : on off : optional incidental ; +feature.subfeature fopt : version : 1 2 : composite incidental ; +feature.compose <fopt-version>2 : <define>FOPT_2 ; + +feature.feature cx1 : on : composite incidental ; +feature.feature cx2 : on : optional incidental ; +feature.subfeature cx2 on : sub : 1 : composite incidental ; +feature.compose <cx1>on : <cx2>on ; +feature.compose <cx2-on:sub>1 : <define>CX_2 ; + +feature.feature sf : a : incidental ; +feature.subfeature sf a : sub : 1 : composite incidental ; +feature.compose <sf-a:sub>1 : <define>SF_1 ; +""") + +t.expand_toolset("jamfile.jam") + +t.run_build_system() +t.expect_addition(["bin/debug/a.check", + "bin/debug/b.check", + "bin/null/release/c.check", + "bin/debug/d.check", + "bin/debug/e.check", + "bin/debug/f.check", + "bin/debug/g.check", + "bin/debug/h.check", + "bin/debug/i.check"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/explicit.py b/src/boost/tools/build/test/explicit.py new file mode 100644 index 00000000..14d42175 --- /dev/null +++ b/src/boost/tools/build/test/explicit.py @@ -0,0 +1,58 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """\ +exe hello : hello.cpp ; +exe hello2 : hello.cpp ; +explicit hello2 ; +""") + +t.write("hello.cpp", "int main() {}\n") + +t.run_build_system() +t.ignore("*.tds") +t.expect_addition(BoostBuild.List("bin/$toolset/debug*/hello") * \ + [".exe", ".obj"]) +t.expect_nothing_more() + +t.run_build_system(["hello2"]) +t.expect_addition("bin/$toolset/debug*/hello2.exe") + +t.rm(".") + + +# Test that 'explicit' used in a helper rule applies to the current project, and +# not to the Jamfile where the helper rule is defined. +t.write("jamroot.jam", """\ +rule myinstall ( name : target ) +{ + install $(name)-bin : $(target) ; + explicit $(name)-bin ; + alias $(name) : $(name)-bin ; +} +""") + +t.write("sub/a.cpp", "\n") +t.write("sub/jamfile.jam", "myinstall dist : a.cpp ;") + +t.run_build_system(subdir="sub") +t.expect_addition("sub/dist-bin/a.cpp") + +t.rm("sub/dist-bin") + +t.write("sub/jamfile.jam", """\ +myinstall dist : a.cpp ; +explicit dist ; +""") + +t.run_build_system(subdir="sub") +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/feature_cxxflags.py b/src/boost/tools/build/test/feature_cxxflags.py new file mode 100755 index 00000000..a4eeb52d --- /dev/null +++ b/src/boost/tools/build/test/feature_cxxflags.py @@ -0,0 +1,37 @@ +#!/usr/bin/python + +# Copyright 2014 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the cxxflags feature + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# cxxflags should be applied to C++ compilation, +# but not to C. +t.write("Jamroot.jam", """ +obj test-cpp : test.cpp : <cxxflags>-DOKAY ; +obj test-c : test.c : <cxxflags>-DBAD ; +""") + +t.write("test.cpp", """ +#ifndef OKAY +#error Cannot compile without OKAY +#endif +""") + +t.write("test.c", """ +#ifdef BAD +#error Cannot compile with BAD +#endif +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/test-cpp.obj") +t.expect_addition("bin/$toolset/debug*/test-c.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/feature_implicit_dependency.py b/src/boost/tools/build/test/feature_implicit_dependency.py new file mode 100644 index 00000000..0b40da1b --- /dev/null +++ b/src/boost/tools/build/test/feature_implicit_dependency.py @@ -0,0 +1,113 @@ +#!/usr/bin/python + +# Copyright (c) Steven Watanabe 2018. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that a single main target can be used for +# implicit dependencies of multiple different types. + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=False) + +t.write("input.sss", "") + +t.write("Jamroot.jam", """ +import type ; +import common ; +import generators ; +import "class" : new ; +import feature : feature ; +import toolset : flags ; + +type.register AAA : aaa ; +type.register BBB : bbb ; +type.register CCC : ccc ; +type.register DDD : ddd ; +type.register SSS : sss ; + +feature aaa-path : : free path ; +feature bbb-path : : free path ; + +class aaa-action : action +{ + rule adjust-properties ( property-set ) + { + local s = [ $(self.targets[1]).creating-subvariant ] ; + return [ $(property-set).add-raw + [ $(s).implicit-includes aaa-path : AAA ] ] ; + } +} + +class aaa-generator : generator +{ + rule action-class ( ) + { + return aaa-action ; + } +} + +class bbb-action : action +{ + rule adjust-properties ( property-set ) + { + local s = [ $(self.targets[1]).creating-subvariant ] ; + return [ $(property-set).add-raw + [ $(s).implicit-includes bbb-path : BBB ] ] ; + } +} + +class bbb-generator : generator +{ + rule action-class ( ) + { + return bbb-action ; + } +} + +generators.register-standard common.copy : SSS : AAA ; +generators.register-standard common.copy : SSS : BBB ; + +# Produce two targets from a single source +rule make-aaa-bbb ( project name ? : property-set : sources * ) +{ + local result ; + local aaa = [ generators.construct $(project) $(name) : AAA : + [ $(property-set).add-raw <location-prefix>a-loc ] : $(sources) ] ; + local bbb = [ generators.construct $(project) $(name) : BBB : + [ $(property-set).add-raw <location-prefix>b-loc ] : $(sources) ] ; + return [ $(aaa[1]).add $(bbb[1]) ] $(aaa[2-]) $(bbb[2-]) ; +} + +generate input : input.sss : <generating-rule>@make-aaa-bbb ; +explicit input ; + +flags make-ccc AAAPATH : <aaa-path> ; +rule make-ccc ( target : sources * : properties * ) +{ + ECHO aaa path\: [ on $(target) return $(AAAPATH) ] ; + common.copy $(target) : $(sources) ; +} + +flags make-ddd BBBPATH : <bbb-path> ; +rule make-ddd ( target : sources * : properties * ) +{ + ECHO bbb path\: [ on $(target) return $(BBBPATH) ] ; + common.copy $(target) : $(sources) ; +} + +generators.register [ new aaa-generator $(__name__).make-ccc : SSS : CCC ] ; +generators.register [ new bbb-generator $(__name__).make-ddd : SSS : DDD ] ; + +# This should have <aaapath>bin/a-loc +ccc output-c : input.sss : <implicit-dependency>input ; +# This should have <bbbpath>bin/b-loc +ddd output-d : input.sss : <implicit-dependency>input ; +""") + +t.run_build_system() +t.expect_output_lines(["aaa path: bin/a-loc", "bbb path: bin/b-loc"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/feature_relevant.py b/src/boost/tools/build/test/feature_relevant.py new file mode 100644 index 00000000..4e7a0c45 --- /dev/null +++ b/src/boost/tools/build/test/feature_relevant.py @@ -0,0 +1,142 @@ +#!/usr/bin/python + +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the <relevant> feature + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("xxx.jam", """ +import type ; +import feature : feature ; +import toolset : flags ; +import generators ; +type.register XXX : xxx ; +type.register YYY : yyy ; +feature xxxflags : : free ; +generators.register-standard xxx.run : YYY : XXX ; +# xxxflags is relevant because it is used by flags +flags xxx.run OPTIONS : <xxxflags> ; +actions run +{ + echo okay > $(<) +} +""") + +t.write("zzz.jam", """ +import xxx ; +import type ; +import feature : feature ; +import generators ; +type.register ZZZ : zzz ; +feature zzz.enabled : off on : propagated ; +# zzz.enabled is relevant because it is used in the generator's +# requirements +generators.register-standard zzz.run : XXX : ZZZ : <zzz.enabled>on ; +actions run +{ + echo okay > $(<) +} +""") + +t.write("aaa.jam", """ +import zzz ; +import type ; +import feature : feature ; +import generators ; +import toolset : flags ; +type.register AAA : aaa ; +feature aaaflags : : free ; +generators.register-standard aaa.run : ZZZ : AAA ; +flags aaa.run OPTIONS : <aaaflags> ; +actions run +{ + echo okay > $(<) +} +""") + +t.write("Jamroot.jam", """ +import xxx ; +import zzz ; +import aaa ; +import feature : feature ; + +# f1 is relevant, because it is composite and <xxxflags> is relevant +feature f1 : n y : composite propagated ; +feature.compose <f1>y : <xxxflags>-no1 ; +# f2 is relevant, because it is used in a conditional +feature f2 : n y : propagated ; +# f3 is relevant, because it is used to choose the target alternative +feature f3 : n y : propagated ; +# f4 is relevant, because it is marked as such explicitly +feature f4 : n y : propagated ; +# f5 is relevant because of the conditional usage-requirements +feature f5 : n y : propagated ; +# f6 is relevant because the indirect conditional indicates so +feature f6 : n y : propagated ; +# f7 is relevant because the icond7 says so +feature f7 : n y : propagated ; + +# The same as f[n], except not propagated +feature g1 : n y : composite ; +feature.compose <g1>y : <xxxflags>-no1 ; +feature g2 : n y ; +feature g3 : n y ; +feature g4 : n y ; +feature g5 : n y ; +feature g6 : n y ; +feature g7 : n y ; + +project : default-build + <f1>y <f2>y <f3>y <f4>y <f5>y <f6>y <f7>y + <g1>y <g2>y <g3>y <g4>y <g5>y <g6>y <g7>y <zzz.enabled>on ; + +rule icond6 ( properties * ) +{ + local result ; + if <f6>y in $(properties) || <g6>y in $(properties) + { + result += <xxxflags>-yes6 ; + } + return $(result) + <relevant>xxxflags:<relevant>f6 + <relevant>xxxflags:<relevant>g6 ; +} + +rule icond7 ( properties * ) +{ + local result ; + if <f7>y in $(properties) || <g7>y in $(properties) + { + result += <aaaflags>-yes7 ; + } + return $(result) + <relevant>aaaflags:<relevant>f7 + <relevant>aaaflags:<relevant>g7 ; +} + +zzz out : in.yyy + : <f2>y:<xxxflags>-no2 <g2>y:<xxxflags>-no2 <relevant>f4 <relevant>g4 + <conditional>@icond6 + : + : <f5>y:<aaaflags>-yes5 <g5>y:<aaaflags>-yes5 <conditional>@icond7 + ; +alias out : : <f3>n ; +alias out : : <g3>n ; +# Features that are relevant for out are also relevant for check-propagate +aaa check-propagate : out ; +""") + +t.write("in.yyy", "") + +t.run_build_system() +t.expect_addition("bin/f1-y/f2-y/f3-y/f4-y/f6-y/g1-y/g2-y/g3-y/g4-y/g6-y/out.xxx") +t.expect_addition("bin/f1-y/f2-y/f3-y/f4-y/f6-y/g1-y/g2-y/g3-y/g4-y/g6-y/zzz.enabled-on/out.zzz") +t.expect_addition("bin/f1-y/f2-y/f3-y/f4-y/f5-y/f6-y/f7-y/zzz.enabled-on/check-propagate.aaa") + +t.cleanup() diff --git a/src/boost/tools/build/test/feature_suppress_import_lib.py b/src/boost/tools/build/test/feature_suppress_import_lib.py new file mode 100644 index 00000000..8dc66672 --- /dev/null +++ b/src/boost/tools/build/test/feature_suppress_import_lib.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the suppress-import-lib feature + +# This used to cause the pdb and the import lib to get mixed up +# if there are any exports. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("Jamroot.jam", """ +lib l : l.cpp : <suppress-import-lib>true ; +""") + +t.write("l.cpp", """ +void +#ifdef _WIN32 +__declspec(dllexport) +#endif +f() {} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/l.obj") +t.expect_addition("bin/$toolset/debug*/l.dll") + +t.cleanup() diff --git a/src/boost/tools/build/test/file_types.py b/src/boost/tools/build/test/file_types.py new file mode 100644 index 00000000..e6d9bf84 --- /dev/null +++ b/src/boost/tools/build/test/file_types.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# +# Copyright 2018 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the mapping of various suffixes +# In particular, .so[.version] needs to +# be mapped as a SHARED_LIB. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("Jamroot.jam", """\ +import type : type ; +ECHO [ type source.c ] ; +ECHO [ type source.cc ] ; +ECHO [ type source.cxx ] ; +ECHO [ type source.cpp ] ; +ECHO [ type source.o ] ; +ECHO [ type source.obj ] ; +ECHO [ type boost_system.lib ] ; +ECHO [ type boost_system.so ] ; +ECHO [ type boost_system.dll ] ; +EXIT [ type boost_system.so.1.66.0 ] : 0 ; +""") + +t.run_build_system(stdout="""\ +C +CPP +CPP +CPP +OBJ +OBJ +STATIC_LIB +SHARED_LIB +SHARED_LIB +SHARED_LIB +""") + +t.cleanup() diff --git a/src/boost/tools/build/test/flags.py b/src/boost/tools/build/test/flags.py new file mode 100644 index 00000000..bdb2b6b7 --- /dev/null +++ b/src/boost/tools/build/test/flags.py @@ -0,0 +1,74 @@ +#!/usr/bin/python + +# Copyright (C) Steven Watanabe 2018 +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the check-has-flag rule + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# We need an object file before we can run the actual test. +t.write('input.cpp', 'void f() {}\n') +t.write('Jamroot.jam', 'obj input : input.cpp ;') +t.run_build_system() + +linker_input = t.glob_file('bin/$toolset/debug*/input.obj') + +# Check every possible result of pass or fail. +t.write('Jamroot.jam', ''' +import flags ; +import modules ; +OBJECT_FILE = [ modules.peek : OBJECT_FILE ] ; +obj fail_cpp : test.cpp : [ check-has-flag <cxxflags>--illegal-flag-cpp + : <define>ERROR : <define>OK ] ; +obj pass_cpp : test.cpp : [ check-has-flag <cxxflags>-DMACRO_CPP + : <define>OK : <define>ERROR ] ; +obj fail_c : test.cpp : [ check-has-flag <cflags>--illegal-flag-c + : <define>ERROR : <define>OK ] ; +obj pass_c : test.cpp : [ check-has-flag <cflags>-DMACRO_C + : <define>OK : <define>ERROR ] ; +obj fail_link : test.cpp : [ check-has-flag <linkflags>--illegal-flag-link + : <define>ERROR : <define>OK ] ; +# The only thing that we can be certain the linker +# will accept is the name of an object file. +obj pass_link : test.cpp : [ check-has-flag <linkflags>$(OBJECT_FILE) + : <define>OK : <define>ERROR ] ; +''') + +t.write('test.cpp', ''' +#ifdef ERROR +#error ERROR defined +#endif +#ifndef OK +#error ERROR not defined +#endif +''') + +# Don't check the status immediately, so that we have a chance +# to print config.log. Also, we need a minimum of d2 to make +# sure that we always see the commands and output. +t.run_build_system(['-sOBJECT_FILE=' + linker_input, '-d2'], status=None) + +if t.status != 0: + log_file = t.read('bin/config.log') + BoostBuild.annotation("config.log", log_file) + t.fail_test(True) + +t.expect_output_lines([' - has --illegal-flag-cpp : no', + ' - has -DMACRO_CPP : yes', + ' - has --illegal-flag-c : no', + ' - has -DMACRO_C : yes', + ' - has --illegal-flag-link : no', + ' - has *bin*/input.* : yes']) +t.expect_addition('bin/$toolset/debug*/fail_cpp.obj') +t.expect_addition('bin/$toolset/debug*/pass_cpp.obj') +t.expect_addition('bin/$toolset/debug*/fail_c.obj') +t.expect_addition('bin/$toolset/debug*/pass_c.obj') +t.expect_addition('bin/$toolset/debug*/fail_link.obj') +t.expect_addition('bin/$toolset/debug*/pass_link.obj') + +t.cleanup() diff --git a/src/boost/tools/build/test/gcc_runtime.py b/src/boost/tools/build/test/gcc_runtime.py new file mode 100644 index 00000000..684afed1 --- /dev/null +++ b/src/boost/tools/build/test/gcc_runtime.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that on gcc, we correctly report a problem when static runtime is +# requested for building a shared library. + +import BoostBuild + +t = BoostBuild.Tester() +t.write("jamroot.jam", "lib hello : hello.cpp ;") +t.write("hello.cpp", "int main() {}\n") + +t.run_build_system(["runtime-link=static"]) +t.expect_output_lines("warning: On gcc, DLLs can not be built with " + "'<runtime-link>static'.") +t.expect_nothing_more() + +t.run_build_system(["link=static", "runtime-link=static"]) +t.expect_addition("bin/$toolset/debug*/link-static*/hello.obj") +t.expect_addition("bin/$toolset/debug*/link-static*/hello.lib") +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/generator_selection.py b/src/boost/tools/build/test/generator_selection.py new file mode 100755 index 00000000..50d4ff3c --- /dev/null +++ b/src/boost/tools/build/test/generator_selection.py @@ -0,0 +1,158 @@ +#!/usr/bin/python + +# Copyright 2008, 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that generators get selected correctly. +# +# We do not use the internal C++-compiler CPP --> OBJ generator to avoid +# problems with specific compilers or their configurations, e.g. IBM's AIX test +# runner 'AIX Version 5.3 TL7 SP5 (5300-07-05-0831)' using the 'IBM XL C/C++ +# for AIX, V12.1 (Version: 12.01.0000.0000)' reporting errors when run with a +# source file whose suffix is not '.cpp'. + +import BoostBuild + + +############################################################################### +# +# test_generator_added_after_already_building_a_target_of_its_target_type() +# ------------------------------------------------------------------------- +# +############################################################################### + +def test_generator_added_after_already_building_a_target_of_its_target_type(): + """ + Regression test for a Boost Build bug causing it to not use a generator + if it got added after already building a target of its target type. + + """ + t = BoostBuild.Tester() + + t.write("dummy.cpp", "void f() {}\n") + + t.write("jamroot.jam", """\ +import common ; +import generators ; +import type ; +type.register MY_OBJ : my_obj ; +generators.register-standard common.copy : CPP : MY_OBJ ; + +# Building this dummy target must not cause a later defined CPP target type +# generator not to be recognized as viable. +my-obj dummy : dummy.cpp ; +alias the-other-obj : Other//other-obj ; +""") + + t.write("Other/source.extension", "A dummy source file.") + + t.write("Other/mygen.jam", """\ +import common ; +import generators ; +import type ; +type.register MY_TYPE : extension ; +generators.register-standard $(__name__).generate-a-cpp-file : MY_TYPE : CPP ; +rule generate-a-cpp-file { ECHO Generating a CPP file... ; } +CREATE-FILE = [ common.file-creation-command ] ; +actions generate-a-cpp-file { $(CREATE-FILE) "$(<)" } +""") + + t.write("Other/mygen.py", """\ +from __future__ import print_function +import b2.build.generators as generators +import b2.build.type as type + +from b2.manager import get_manager + +import os + +type.register('MY_TYPE', ['extension']) +generators.register_standard('mygen.generate-a-cpp-file', ['MY_TYPE'], ['CPP']) +if os.name == 'nt': + action = 'echo void g() {} > "$(<)"' +else: + action = 'echo "void g() {}" > "$(<)"' +def f(*args): + print("Generating a CPP file...") + +get_manager().engine().register_action("mygen.generate-a-cpp-file", action, + function=f) +""") + + t.write("Other/jamfile.jam", """\ +import mygen ; +my-obj other-obj : source.extension ; +""") + + t.run_build_system() + t.expect_output_lines("Generating a CPP file...") + t.expect_addition("bin/dummy.my_obj") + t.expect_addition("Other/bin/other-obj.cpp") + t.expect_addition("Other/bin/other-obj.my_obj") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# test_using_a_derived_source_type_created_after_generator_already_used() +# ----------------------------------------------------------------------- +# +############################################################################### + +def test_using_a_derived_source_type_created_after_generator_already_used(): + """ + Regression test for a Boost Build bug causing it to not use a generator + with a source type derived from one of the generator's sources but created + only after already using the generateor. + + """ + t = BoostBuild.Tester() + + t.write("dummy.xxx", "Hello. My name is Peter Pan.\n") + + t.write("jamroot.jam", """\ +import common ; +import generators ; +import type ; +type.register XXX : xxx ; +type.register YYY : yyy ; +generators.register-standard common.copy : XXX : YYY ; + +# Building this dummy target must not cause a later defined XXX2 target type not +# to be recognized as a viable source type for building YYY targets. +yyy dummy : dummy.xxx ; +alias the-test-output : Other//other ; +""") + + t.write("Other/source.xxx2", "Hello. My name is Tinkerbell.\n") + + t.write("Other/jamfile.jam", """\ +import type ; +type.register XXX2 : xxx2 : XXX ; +# We are careful not to do anything between defining our new XXX2 target type +# and using the XXX --> YYY generator that could potentially cover the Boost +# Build bug by clearing its internal viable source target type state. +yyy other : source.xxx2 ; +""") + + t.run_build_system() + t.expect_addition("bin/dummy.yyy") + t.expect_addition("Other/bin/other.yyy") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +test_generator_added_after_already_building_a_target_of_its_target_type() +test_using_a_derived_source_type_created_after_generator_already_used() diff --git a/src/boost/tools/build/test/generators_test.py b/src/boost/tools/build/test/generators_test.py new file mode 100644 index 00000000..f612a25e --- /dev/null +++ b/src/boost/tools/build/test/generators_test.py @@ -0,0 +1,433 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Dave Abrahams +# Copyright 2002, 2003, 2004, 2005 Vladimir Prus +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import re + + +def test_basic(): + t = BoostBuild.Tester() + __write_appender(t, "appender.jam") + t.write("a.cpp", "") + t.write("b.cxx", "") + t.write("c.tui", "") + t.write("d.wd", "") + t.write("e.cpp", "") + t.write("x.l", "") + t.write("y.x_pro", "") + t.write("z.cpp", "") + t.write("lib/c.cpp", "int bar() { return 0; }\n") + t.write("lib/jamfile.jam", "my-lib auxilliary : c.cpp ;") + t.write("jamroot.jam", +r"""import appender ; + +import "class" : new ; +import generators ; +import type ; + + +################################################################################ +# +# We use our own custom EXE, LIB & OBJ target generators as using the regular +# ones would force us to have to deal with different compiler/linker specific +# 'features' that really have nothing to do with this test. For example, IBM XL +# C/C++ for AIX, V12.1 (Version: 12.01.0000.0000) compiler exits with a non-zero +# exit code and thus fails our build when run with a source file using an +# unknown suffix like '.marked_cpp'. +# +################################################################################ + +type.register MY_EXE : my_exe ; +type.register MY_LIB : my_lib ; +type.register MY_OBJ : my_obj ; + +appender.register compile-c : C : MY_OBJ ; +appender.register compile-cpp : CPP : MY_OBJ ; +appender.register link-lib composing : MY_OBJ : MY_LIB ; +appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ; + + +################################################################################ +# +# LEX --> C +# +################################################################################ + +type.register LEX : l ; + +appender.register lex-to-c : LEX : C ; + + +################################################################################ +# +# /--> tUI_H --\ +# tUI --< >--> CPP +# \------------/ +# +################################################################################ + +type.register tUI : tui ; +type.register tUI_H : tui_h ; + +appender.register ui-to-cpp : tUI tUI_H : CPP ; +appender.register ui-to-h : tUI : tUI_H ; + + +################################################################################ +# +# /--> X1 --\ +# X_PRO --< >--> CPP +# \--> X2 --/ +# +################################################################################ + +type.register X1 : x1 ; +type.register X2 : x2 ; +type.register X_PRO : x_pro ; + +appender.register x1-x2-to-cpp : X1 X2 : CPP ; +appender.register x-pro-to-x1-x2 : X_PRO : X1 X2 ; + + +################################################################################ +# +# When the main target type is NM_EXE, build OBJ from CPP-MARKED and not from +# anything else, e.g. directly from CPP. +# +################################################################################ + +type.register CPP_MARKED : marked_cpp : CPP ; +type.register POSITIONS : positions ; +type.register NM.TARGET.CPP : target_cpp : CPP ; +type.register NM_EXE : : MY_EXE ; + +appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ; +appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ; + +class "nm::target::cpp-obj-generator" : generator +{ + rule __init__ ( id ) + { + generator.__init__ $(id) : NM.TARGET.CPP : MY_OBJ ; + generator.set-rule-name appender.appender ; + } + + rule requirements ( ) + { + return <main-target-type>NM_EXE ; + } + + rule run ( project name ? : properties * : source : multiple ? ) + { + if [ $(source).type ] = CPP + { + local converted = [ generators.construct $(project) : NM.TARGET.CPP + : $(properties) : $(source) ] ; + if $(converted) + { + return [ generators.construct $(project) : MY_OBJ : + $(properties) : $(converted[2]) ] ; + } + } + } +} +generators.register [ new "nm::target::cpp-obj-generator" target-obj ] ; +generators.override target-obj : all ; + + +################################################################################ +# +# A more complex test case scenario with the following generators: +# 1. WHL --> CPP, WHL_LR0, H, H(%_symbols) +# 2. DLP --> CPP +# 3. WD --> WHL(%_parser) DLP(%_lexer) +# 4. A custom generator of higher priority than generators 1. & 2. that helps +# disambiguate between them when generating CPP files from WHL and DLP +# sources. +# +################################################################################ + +type.register WHL : whl ; +type.register DLP : dlp ; +type.register WHL_LR0 : lr0 ; +type.register WD : wd ; + +local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H + H(%_symbols) ] ; +local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ; +appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ; + +class wd-to-cpp : generator +{ + rule __init__ ( id : sources * : targets * ) + { + generator.__init__ $(id) : $(sources) : $(targets) ; + } + + rule run ( project name ? : property-set : source ) + { + local new-sources = $(source) ; + if ! [ $(source).type ] in WHL DLP + { + local r1 = [ generators.construct $(project) $(name) : WHL : + $(property-set) : $(source) ] ; + local r2 = [ generators.construct $(project) $(name) : DLP : + $(property-set) : $(source) ] ; + new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ; + } + + local result ; + for local i in $(new-sources) + { + local t = [ generators.construct $(project) $(name) : CPP : + $(property-set) : $(i) ] ; + result += $(t[2-]) ; + } + return $(result) ; + } +} +generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ; +generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ; +generators.register [ new wd-to-cpp $(__name__).wd-to-cpp : : CPP ] ; + + +################################################################################ +# +# Declare build targets. +# +################################################################################ + +# This should not cause two CPP --> MY_OBJ constructions for a.cpp or b.cpp. +my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ; +my-exe f : a.cpp b.cxx obj_1 obj_2 lib//auxilliary ; + +# This should cause two CPP --> MY_OBJ constructions for z.cpp. +my-obj obj_1 : z.cpp ; +my-obj obj_2 : z.cpp ; + +nm-exe e : e.cpp ; +""") + + t.run_build_system() + t.expect_addition("bin/" * BoostBuild.List("a.my_exe " + "a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp " + "d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h " + "d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp " + "y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe " + "f.my_exe obj_1.my_obj obj_2.my_obj")) + t.expect_addition("lib/bin/" * BoostBuild.List("c.my_obj " + "auxilliary.my_lib")) + t.expect_nothing_more() + + folder = "bin" + t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'") + t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'") + t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'") + + lines = t.stdout().splitlines() + source_lines = [x for x in lines if re.match("^ Sources: '", x)] + if not __match_count_is(source_lines, "'z.cpp'", 2): + BoostBuild.annotation("failure", "z.cpp must be compiled exactly " + "twice.") + t.fail_test(1) + if not __match_count_is(source_lines, "'a.cpp'", 1): + BoostBuild.annotation("failure", "a.cpp must be compiled exactly " + "once.") + t.fail_test(1) + t.cleanup() + + +def test_generated_target_names(): + """ + Test generator generated target names. Unless given explicitly, target + names should be determined based on their specified source names. All + sources for generating a target need to have matching names in order for + Boost Build to be able to implicitly determine the target's name. + + We use the following target generation structure with differently named + BBX targets: + /---> BB1 ---\ + AAA --<----> BB2 ---->--> CCC --(composing)--> DDD + \---> BB3 ---/ + + The extra generator at the end is needed because generating a top-level + CCC target directly would requires us to explicitly specify a name for it. + The extra generator needs to be composing in order not to explicitly + request a specific name for its CCC source target based on its own target + name. + + We also check for a regression where only the first two sources were + checked to see if their names match. Note that we need to try out all file + renaming combinations as we do not know what ordering Boost Build is going + to use when passing in those files as generator sources. + + """ + jamfile_template = """\ +import type ; +type.register AAA : _a ; +type.register BB1 : _b1 ; +type.register BB2 : _b2 ; +type.register BB3 : _b3 ; +type.register CCC : _c ; +type.register DDD : _d ; + +import appender ; +appender.register aaa-to-bbX : AAA : BB1%s BB2%s BB3%s ; +appender.register bbX-to-ccc : BB1 BB2 BB3 : CCC ; +appender.register ccc-to-ddd composing : CCC : DDD ; + +ddd _xxx : _xxx._a ; +""" + + t = BoostBuild.Tester() + __write_appender(t, "appender.jam") + t.write("_xxx._a", "") + + def test_one(t, rename1, rename2, rename3, status): + def f(rename): + if rename: return "(%_x)" + return "" + + jamfile = jamfile_template % (f(rename1), f(rename2), f(rename3)) + t.write("jamroot.jam", jamfile, wait=False) + + # Remove any preexisting targets left over from a previous test run + # so we do not have to be careful about tracking which files have been + # newly added and which preexisting ones have only been modified. + t.rm("bin") + + t.run_build_system(status=status) + + if status: + t.expect_output_lines("*.bbX-to-ccc: source targets have " + "different names: cannot determine target name") + else: + def suffix(rename): + if rename: return "_x" + return "" + name = "bin/_xxx" + e = t.expect_addition + e("%s%s._b1" % (name, suffix(rename1))) + e("%s%s._b2" % (name, suffix(rename2))) + e("%s%s._b3" % (name, suffix(rename3))) + e("%s%s._c" % (name, suffix(rename1 and rename2 and rename3))) + e("%s._d" % name) + t.expect_nothing_more() + + test_one(t, False, False, False, status=0) + test_one(t, True , False, False, status=1) + test_one(t, False, True , False, status=1) + test_one(t, False, False, True , status=1) + test_one(t, True , True , False, status=1) + test_one(t, True , False, True , status=1) + test_one(t, False, True , True , status=1) + test_one(t, True , True , True , status=0) + t.cleanup() + + +def __match_count_is(lines, pattern, expected): + count = 0 + for x in lines: + if re.search(pattern, x): + count += 1 + if count > expected: + return False + return count == expected + + +def __write_appender(t, name): + t.write(name, +r"""# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Support for registering test generators that construct their targets by +# simply appending their given input data, e.g. list of sources & targets. + +import "class" : new ; +import generators ; +import modules ; +import sequence ; + +rule register ( id composing ? : source-types + : target-types + ) +{ + local caller-module = [ CALLER_MODULE ] ; + id = $(caller-module).$(id) ; + local g = [ new generator $(id) $(composing) : $(source-types) : + $(target-types) ] ; + $(g).set-rule-name $(__name__).appender ; + generators.register $(g) ; + return $(id) ; +} + +if [ modules.peek : NT ] +{ + X = ")" ; + ECHO_CMD = (echo. ; +} +else +{ + X = \" ; + ECHO_CMD = "echo $(X)" ; +} + +local appender-runs ; + +# We set up separate actions for building each target in order to avoid having +# to iterate over them in action (i.e. shell) code. We have to be extra careful +# though to achieve the exact same effect as if doing all the work in just one +# action. Otherwise Boost Jam might, under some circumstances, run only some of +# our actions. To achieve this we register a series of actions for all the +# targets (since they all have the same target list - either all or none of them +# get run independent of which target actually needs to get built), each +# building only a single target. Since all our actions use the same targets, we +# can not use 'on-target' parameters to pass data to a specific action so we +# pass them using the second 'sources' parameter which our actions then know how +# to interpret correctly. This works well since Boost Jam does not automatically +# add dependency relations between specified action targets & sources and so the +# second argument, even though most often used to pass in a list of sources, can +# actually be used for passing in any type of information. +rule appender ( targets + : sources + : properties * ) +{ + appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ; + local target-index = 0 ; + local target-count = [ sequence.length $(targets) ] ; + local original-targets ; + for t in $(targets) + { + target-index = [ CALC $(target-index) + 1 ] ; + local appender-run = $(appender-runs) ; + if $(targets[2])-defined + { + appender-run += "[$(target-index)/$(target-count)]" ; + } + append $(targets) : $(appender-run:J=" ") $(t) $(sources) ; + } +} + +actions append +{ + $(ECHO_CMD)-------------------------------------------------$(X) + $(ECHO_CMD)Appender run: $(>[1])$(X) + $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])" + $(ECHO_CMD)Target group: $(<:J=' ')$(X) + $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])" + $(ECHO_CMD) Target: '$(>[2])'$(X) + $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])" + $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X) + $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])" + $(ECHO_CMD)=================================================$(X) + $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])" +} +""") + + +test_basic() +test_generated_target_names() diff --git a/src/boost/tools/build/test/implicit_dependency.py b/src/boost/tools/build/test/implicit_dependency.py new file mode 100644 index 00000000..dac9c7c5 --- /dev/null +++ b/src/boost/tools/build/test/implicit_dependency.py @@ -0,0 +1,81 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the <implicit-dependency> is respected even if the target referred to is +# not built itself, but only referred to by <implicit-dependency>. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +make a.h : : gen-header ; +explicit a.h ; + +exe hello : hello.cpp : <implicit-dependency>a.h ; + +import os ; +if [ os.name ] = NT +{ + actions gen-header + { + echo int i; > $(<) + } +} +else +{ + actions gen-header + { + echo "int i;" > $(<) + } +} +""") + +t.write("hello.cpp", """ +#include "a.h" +int main() { return i; } +""") + + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/hello.exe") + +t.rm("bin") + +t.write("jamroot.jam", """ +make dir/a.h : : gen-header ; +explicit dir/a.h ; + +exe hello : hello.cpp : <implicit-dependency>dir/a.h ; + +import os ; +if [ os.name ] = NT +{ + actions gen-header + { + echo int i; > $(<) + } +} +else +{ + actions gen-header + { + echo "int i;" > $(<) + } +} +""") + +t.write("hello.cpp", """ +#include "dir/a.h" +int main() { return i; } +""") +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/indirect_conditional.py b/src/boost/tools/build/test/indirect_conditional.py new file mode 100644 index 00000000..b59c7800 --- /dev/null +++ b/src/boost/tools/build/test/indirect_conditional.py @@ -0,0 +1,148 @@ +#!/usr/bin/python + +# Copyright (C) 2006. Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +def test_basic(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +exe a1 : a1.cpp : <conditional>@a1-rule ; +rule a1-rule ( properties * ) +{ + if <variant>debug in $(properties) + { + return <define>OK ; + } +} + +exe a2 : a2.cpp : <conditional>@$(__name__).a2-rule + <variant>debug:<optimization>speed ; +rule a2-rule ( properties * ) +{ + if <optimization>speed in $(properties) + { + return <define>OK ; + } +} + +exe a3 : a3.cpp : + <conditional>@$(__name__).a3-rule-1 + <conditional>@$(__name__).a3-rule-2 ; +rule a3-rule-1 ( properties * ) +{ + if <optimization>speed in $(properties) + { + return <define>OK ; + } +} +rule a3-rule-2 ( properties * ) +{ + if <variant>debug in $(properties) + { + return <optimization>speed ; + } +} +""") + + t.write("a1.cpp", "#ifdef OK\nint main() {}\n#endif\n") + t.write("a2.cpp", "#ifdef OK\nint main() {}\n#endif\n") + t.write("a3.cpp", "#ifdef OK\nint main() {}\n#endif\n") + + t.run_build_system() + + t.expect_addition("bin/$toolset/debug*/a1.exe") + t.expect_addition("bin/$toolset/debug/optimization-speed*/a2.exe") + t.expect_addition("bin/$toolset/debug/optimization-speed*/a3.exe") + + t.cleanup() + +def test_inherit(): + """Tests that paths etc. are handled correctly when an indirect + conditional is inherited by a subproject.""" + t = BoostBuild.Tester(use_test_config=False) + t.write("Jamroot.jam", """ +import feature ; +import indirect ; +exe d1 : d1.cpp ; +explicit d1 ; +project : requirements <conditional>@c1 ; +build-project subdir ; +feature.feature myrule : : free ; +rule c1 ( properties * ) +{ + return <dependency>d1 <include>include <myrule>@parent-generate ; +} +rule parent-generate ( project name : property-set : sources * ) +{ + return $(sources) ; +} +rule my-generate ( project name : property-set : sources * ) +{ + local r = [ $(property-set).get <myrule> ] ; + r = [ MATCH @(.*) : $(r) ] ; + return [ indirect.call + $(r) $(project) $(name) : $(property-set) : $(sources) ] ; +} +""") + t.write("d1.cpp", "int main(){}\n") + t.write("subdir/Jamfile", """ +generate srcs : main.cpp : <generating-rule>@my-generate ; +exe main : srcs ; +""") + t.write("include/a.h", "") + t.write("subdir/main.cpp", "#include <a.h>\nint main() {}\n") + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/d1.obj") + t.expect_addition("bin/$toolset/debug*/d1.exe") + t.expect_addition("subdir/bin/$toolset/debug*/main.obj") + t.expect_addition("subdir/bin/$toolset/debug*/main.exe") + t.expect_nothing_more() + t.cleanup() + +def test_glob_in_indirect_conditional(): + """ + Regression test: project-rules.glob rule run from inside an indirect + conditional should report an error as it depends on the 'currently loaded + project' concept and indirect conditional rules get called only after all + the project modules have already finished loading. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", """\ +use-project /library-example/foo : util/foo ; +build-project app ; +""") + t.write("app/app.cpp", "int main() {}\n"); + t.write("app/jamfile.jam", "exe app : app.cpp /library-example/foo//bar ;") + t.write("util/foo/bar.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() {} +""") + t.write("util/foo/jamfile.jam", """\ +rule print-my-sources ( properties * ) +{ + ECHO My sources: ; + ECHO [ glob *.cpp ] ; +} +lib bar : bar.cpp : <conditional>@print-my-sources ; +""") + + t.run_build_system(status=1) + t.expect_output_lines(["My sources:", "bar.cpp"], False) + t.expect_output_lines("error: Reference to the project currently being " + "loaded requested when there was no project module being loaded.") + + t.cleanup() + + +test_basic() +test_inherit() +test_glob_in_indirect_conditional() diff --git a/src/boost/tools/build/test/inherit_toolset.py b/src/boost/tools/build/test/inherit_toolset.py new file mode 100644 index 00000000..f80b1fec --- /dev/null +++ b/src/boost/tools/build/test/inherit_toolset.py @@ -0,0 +1,100 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import string + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("a.cpp", "\n") + +t.write("yfc1.jam", """\ +import feature ; +import generators ; + +feature.extend toolset : yfc1 ; +rule init ( ) { } + +generators.register-standard yfc1.compile : CPP : OBJ : <toolset>yfc1 ; +generators.register-standard yfc1.link : OBJ : EXE : <toolset>yfc1 ; + +actions compile { yfc1-compile } +actions link { yfc1-link } +""") + +t.write( + 'yfc1.py', +""" +from b2.build import feature, generators +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +feature.extend('toolset', ['yfc1']) + +generators.register_standard('yfc1.compile', ['CPP'], ['OBJ'], ['<toolset>yfc1']) +generators.register_standard('yfc1.link', ['OBJ'], ['EXE'], ['<toolset>yfc1']) + +ENGINE.register_action( + 'yfc1.compile', + 'yfc1-compile' +) + +ENGINE.register_action( + 'yfc1.link', + 'yfc1-link' +) + +def init(*args): + pass + +""" +) + +t.write("yfc2.jam", """\ +import feature ; +import toolset ; + +feature.extend toolset : yfc2 ; +toolset.inherit yfc2 : yfc1 ; +rule init ( ) { } + +actions link { yfc2-link } +""") + +t.write( + 'yfc2.py', +""" +from b2.build import feature, toolset +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +feature.extend('toolset', ['yfc2']) +toolset.inherit('yfc2', 'yfc1') + +ENGINE.register_action('yfc2.link', 'yfc2-link') + +def init(*args): + pass +""" +) + +t.write("jamfile.jam", "exe a : a.cpp ;") +t.write("jamroot.jam", "using yfc1 ;") + +t.run_build_system(["-n", "-d2", "yfc1"]) +t.fail_test(t.stdout().find("yfc1-link") == -1) + +# Make sure we do not have to explicitly 'use' yfc1. +t.write("jamroot.jam", "using yfc2 ;") + +t.run_build_system(["-n", "-d2", "yfc2"]) +t.fail_test(t.stdout().find("yfc2-link") == -1) + +t.cleanup() diff --git a/src/boost/tools/build/test/inherited_dependency.py b/src/boost/tools/build/test/inherited_dependency.py new file mode 100755 index 00000000..ae939f48 --- /dev/null +++ b/src/boost/tools/build/test/inherited_dependency.py @@ -0,0 +1,237 @@ +#!/usr/bin/python +# +# Copyright (c) 2008 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt) or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +tester = BoostBuild.Tester(use_test_config=False) + + +################################################################################ +# +# Test without giving the project an explicit id. +# +################################################################################ + +tester.write("jamroot.jam", """ +lib test : test.cpp ; +project : requirements <library>test ; +build-project a ; +""") + +tester.write("test.cpp", """ +#ifdef _WIN32 + __declspec(dllexport) +#endif +void foo() {} +""") + +tester.write("a/test1.cpp", """ +int main() {} +""") + +tester.write("a/jamfile.jam", """ +exe test1 : test1.cpp ; +""") + +tester.run_build_system() + +tester.expect_addition("bin/$toolset/debug*/test.obj") +tester.expect_addition("a/bin/$toolset/debug*/test1.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# Run the same test from the "a" directory. +# +################################################################################ + +tester.run_build_system(subdir="a") + +tester.expect_addition("bin/$toolset/debug*/test.obj") +tester.expect_addition("a/bin/$toolset/debug*/test1.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# This time, do give the project an id. +# +################################################################################ + +tester.write("jamroot.jam", """ +lib test : test.cpp ; +project test_project : requirements <library>test ; +build-project a ; +""") + +tester.run_build_system() + +tester.expect_addition("bin/$toolset/debug*/test.obj") +tester.expect_addition("a/bin/$toolset/debug*/test1.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# Now, give the project an id in its attributes. +# +################################################################################ + +tester.write("jamroot.jam", """ +lib test : test.cpp ; +project : id test_project : requirements <library>test ; +build-project a ; +""") + +tester.run_build_system() + +tester.expect_addition("bin/$toolset/debug*/test.obj") +tester.expect_addition("a/bin/$toolset/debug*/test1.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# Give the project an id in both ways at once. +# +################################################################################ + +tester.write("jamroot.jam", """ +lib test : test.cpp ; +project test_project1 : id test_project : requirements <library>test ; +build-project a ; +""") + +tester.run_build_system() + +tester.expect_addition("bin/$toolset/debug*/test.obj") +tester.expect_addition("a/bin/$toolset/debug*/test1.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# Test an absolute path in native format. +# +################################################################################ + +tester.write("jamroot.jam", """ +import path ; +path-constant here : . ; +current-location = [ path.native [ path.root [ path.make $(here) ] [ path.pwd ] + ] ] ; +project test : requirements <source>$(current-location)/a/test1.cpp ; +exe test : test.cpp ; +""") + +tester.run_build_system() +tester.expect_addition("bin/$toolset/debug*/test.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# Test an absolute path in canonical format. +# +################################################################################ + +tester.write("jamroot.jam", """ +import path ; +path-constant here : . ; +current-location = [ path.root [ path.make $(here) ] [ path.pwd ] ] ; +project test : requirements <source>$(current-location)/a/test1.cpp ; +exe test : test.cpp ; +""") + +tester.run_build_system() +tester.expect_addition("bin/$toolset/debug*/test.exe") + +tester.rm("bin") +tester.rm("a/bin") + + +################################################################################ +# +# Test dependency properties (e.g. <source>) whose targets are specified using a +# relative path. +# +################################################################################ + +# Use jamroot.jam rather than jamfile.jam to avoid inheriting the <source> from +# the parent as that would would make test3 a source of itself. +tester.write("b/jamroot.jam", """ +obj test3 : test3.cpp ; +""") + +tester.write("b/test3.cpp", """ +void bar() {} +""") + +tester.write("jamroot.jam", """ +project test : requirements <source>b//test3 ; +build-project a ; +""") + +tester.write("a/jamfile.jam", """ +exe test : test1.cpp ; +""") + +tester.write("a/test1.cpp", """ +void bar(); +int main() { bar(); } +""") + +tester.run_build_system() +tester.expect_addition("b/bin/$toolset/debug*/test3.obj") +tester.expect_addition("a/bin/$toolset/debug*/test.exe") + +tester.rm("bin") +tester.rm("a") +tester.rm("jamroot.jam") +tester.rm("test.cpp") + + +################################################################################ +# +# Test that source-location is respected. +# +################################################################################ + +tester.write("build/jamroot.jam", """ +project : requirements <source>test.cpp : source-location ../src ; +""") + +tester.write("src/test.cpp", """ +int main() {} +""") + +tester.write("build/a/jamfile.jam", """ +project : source-location ../../a_src ; +exe test : test1.cpp ; +""") + +tester.write("a_src/test1.cpp", """ +""") + +tester.run_build_system(subdir="build/a") +tester.expect_addition("build/a/bin/$toolset/debug*/test.exe") + +tester.cleanup() diff --git a/src/boost/tools/build/test/inline.py b/src/boost/tools/build/test/inline.py new file mode 100644 index 00000000..03d91a5d --- /dev/null +++ b/src/boost/tools/build/test/inline.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +# Copyright 2003, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """\ +project : requirements <link>static ; +exe a : a.cpp [ lib helper : helper.cpp ] ; +""") + +t.write("a.cpp", """\ +extern void helper(); +int main() {} +""") + +t.write("helper.cpp", "void helper() {}\n") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a__helper.lib") +t.rm("bin/$toolset/debug*/a__helper.lib") + +t.run_build_system(["a__helper"]) +t.expect_addition("bin/$toolset/debug*/a__helper.lib") + +t.rm("bin") + + +# Now check that inline targets with the same name but present in different +# places are not confused between each other, and with top-level targets. +t.write("jamroot.jam", """\ +project : requirements <link>static ; +exe a : a.cpp [ lib helper : helper.cpp ] ; +exe a2 : a.cpp [ lib helper : helper.cpp ] ; +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug/link-static*/a.exe") +t.expect_addition("bin/$toolset/debug*/a__helper.lib") +t.expect_addition("bin/$toolset/debug*/a2__helper.lib") + + +# Check that the 'alias' target does not change the name of inline targets, and +# that inline targets are explicit. +t.write("jamroot.jam", """\ +project : requirements <link>static ; +alias a : [ lib helper : helper.cpp ] ; +explicit a ; +""") +t.rm("bin") + +t.run_build_system() +t.expect_nothing_more() + +t.run_build_system(["a"]) +t.expect_addition("bin/$toolset/debug*/helper.lib") + +t.cleanup() diff --git a/src/boost/tools/build/test/lib_source_property.py b/src/boost/tools/build/test/lib_source_property.py new file mode 100644 index 00000000..24a90773 --- /dev/null +++ b/src/boost/tools/build/test/lib_source_property.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Regression test: if a library had no explicit sources, but only <source> +# properties, it was built as if it were a searched library, and the specified +# sources were not compiled. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +lib a : : <source>a.cpp ; +""") + +t.write("a.cpp", """ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() {} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.obj") + +t.rm("bin") + + +# Now try with <conditional>. +t.write("jamroot.jam", """ +rule test ( properties * ) +{ + return <source>a.cpp ; +} +lib a : : <conditional>@test ; +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/lib_zlib.py b/src/boost/tools/build/test/lib_zlib.py new file mode 100755 index 00000000..04d32ba7 --- /dev/null +++ b/src/boost/tools/build/test/lib_zlib.py @@ -0,0 +1,184 @@ +#!/usr/bin/python + +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Build from source +t.write("zlib/zlib.h", 'zlib') +t.write("zlib/deflate.c", 'deflate') + +t.write("Jamroot.jam", """ +path-constant here : . ; +using zlib : : <source>$(here)/zlib ; +alias zlib : /zlib//zlib : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, ''' +source_file('deflate.c', 'deflate') +action('-c -x c -I./zlib -o $deflate.o $deflate.c') +action('-c -x c -I./zlib -DZLIB_DLL -o $deflate-shared.o $deflate.c') +action('--dll $deflate-shared.o -o $deflate.so') +action('--archive $deflate.o -o $deflate.a') +''') + +t.run_build_system() +t.expect_addition('bin/standalone/zlib/mock/debug/z.dll') +t.expect_addition('bin/standalone/zlib/mock/debug/link-static/z.lib') + +# Build from source specified in the environment +t.rm('bin') +t.rm('zlib') + +t.write("zlib root/zlib.h", 'zlib') +t.write("zlib root/deflate.c", 'deflate') + +t.write("Jamroot.jam", """ +using zlib ; +alias zlib : /zlib//zlib : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, ''' +source_file('deflate.c', 'deflate') +action(['-c', '-x', 'c', '-I./zlib root', '-o', '$deflate.o', '$deflate.c']) +action(['-c', '-x', 'c', '-I./zlib root', '-DZLIB_DLL', '-o', '$deflate-shared.o', '$deflate.c']) +action('--dll $deflate-shared.o -o $deflate.so') +action('--archive $deflate.o -o $deflate.a') +''') +t.run_build_system(['-sZLIB_SOURCE=zlib root']) +t.expect_addition('bin/standalone/zlib/mock/debug/z.dll') +t.expect_addition('bin/standalone/zlib/mock/debug/link-static/z.lib') + + +t.rm('zlib root') + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('zlib.h.cpp', '#include <zlib.h>\\n') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zlib ; +exe test : test.cpp /zlib//zlib : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=z -o $config.exe') +action('-c -x c++ $zlib.h.cpp -o $zlib.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=z -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zlib ; +exe test : test.cpp /zlib//zlib : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=z -o $config.exe') +action('-c -x c++ $zlib.h.cpp -o $zlib.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=z -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zlib : : <name>myzlib <include>$(here)/zlib <search>$(here)/zlib ; +exe test : test.cpp /zlib//zlib : : <link>static <link>shared ; +""") + +t.write('zlib/zlib.h', 'zlib') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./zlib --static-lib=myzlib -o $config.exe') +action('-c -x c++ $test.cpp -I./zlib -o $test.o') +action('$test.o -L./zlib --static-lib=myzlib -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zlib : : <name>myzlib <include>$(here)/zlib <search>$(here)/zlib ; +exe test : test.cpp /zlib//zlib : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./zlib --shared-lib=myzlib -o $config.exe') +action('-c -x c++ $test.cpp -I./zlib -o $test.o') +action('$test.o -L./zlib --shared-lib=myzlib -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - both static and shared libraries +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zlib : : <name>myzlib <include>$(here)/zlib <search>$(here)/zlib ; +exe test : test.cpp /zlib//zlib + : <link>shared:<define>SHARED : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./zlib --static-lib=myzlib -o $config.exe') +action('$main.o -L./zlib --shared-lib=myzlib -o $config.exe') +action('-c -x c++ $test.cpp -I./zlib -o $test-static.o') +action('-c -x c++ $test.cpp -I./zlib -DSHARED -o $test-shared.o') +action('$test-static.o -L./zlib --static-lib=myzlib -o $test') +action('$test-shared.o -L./zlib --shared-lib=myzlib -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization from the environment +t.rm('bin') +t.write('Jamroot.jam', """ +using zlib ; +exe test : test.cpp /zlib//zlib + : : <link>static <link>shared ; +""") +t.write('zlib root/zlib.h', 'zlib') +MockToolset.set_expected(t, common_stuff + ''' +action(['$main.o', '-L./zlib root', '--shared-lib=myzlib', '-o', '$config.exe']) +action(['-c', '-x', 'c++', '$test.cpp', '-I./zlib root', '-o', '$test.o']) +action(['$test.o', '-L./zlib root', '--shared-lib=myzlib', '-o', '$test']) +''') +t.run_build_system(['-sZLIB_INCLUDE=zlib root', + '-sZLIB_LIBRARY_PATH=zlib root', + '-sZLIB_NAME=myzlib']) +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/libjpeg.py b/src/boost/tools/build/test/libjpeg.py new file mode 100755 index 00000000..e6a5c2ba --- /dev/null +++ b/src/boost/tools/build/test/libjpeg.py @@ -0,0 +1,119 @@ +#!/usr/bin/python + +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Build from source +t.write("libjpeg/jpeglib.h", 'libjpeg') +t.write("libjpeg/jerror.c", 'jpeg') + +t.write("Jamroot.jam", """ +path-constant here : . ; +using libjpeg : : <source>$(here)/libjpeg ; +alias libjpeg : /libjpeg//libjpeg : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, ''' +source_file('jerror.c', 'jpeg') +action('-c -x c -I./libjpeg -o $jerror.o $jerror.c') +action('--dll $jerror.o -o $jpeg.so') +action('--archive $jerror.o -o $jpeg.a') +''') + +t.run_build_system() +t.expect_addition('bin/standalone/libjpeg/mock/debug/jpeg.dll') +t.expect_addition('bin/standalone/libjpeg/mock/debug/link-static/jpeg.lib') + +t.rm('libjpeg') + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('jpeg.h.cpp', '#include <stdio.h>\\n#include <jpeglib.h>\\n') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libjpeg ; +exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=jpeg -o $config.exe') +action('-c -x c++ $jpeg.h.cpp -o $jpeg.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=jpeg -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libjpeg ; +exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=jpeg -o $config.exe') +action('-c -x c++ $jpeg.h.cpp -o $jpeg.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=jpeg -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libjpeg : : <name>mylibjpeg <include>$(here)/libjpeg <search>$(here)/libjpeg ; +exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ; +""") + +t.write('libjpeg/jpeglib.h', 'libjpeg') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./libjpeg --static-lib=mylibjpeg -o $config.exe') +action('-c -x c++ $test.cpp -I./libjpeg -o $test.o') +action('$test.o -L./libjpeg --static-lib=mylibjpeg -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libjpeg : : <name>mylibjpeg <include>$(here)/libjpeg <search>$(here)/libjpeg ; +exe test : test.cpp /libjpeg//libjpeg : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./libjpeg --shared-lib=mylibjpeg -o $config.exe') +action('-c -x c++ $test.cpp -I./libjpeg -o $test.o') +action('$test.o -L./libjpeg --shared-lib=mylibjpeg -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/liblzma.py b/src/boost/tools/build/test/liblzma.py new file mode 100755 index 00000000..6bc767fb --- /dev/null +++ b/src/boost/tools/build/test/liblzma.py @@ -0,0 +1,118 @@ +#!/usr/bin/python + +# Copy-paste-modify from zlib.py +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('lzma.h.cpp', '#include <lzma.h>\\n') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using lzma ; +exe test : test.cpp /lzma//lzma : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=lzma -o $config.exe') +action('-c -x c++ $lzma.h.cpp -o $lzma.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=lzma -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using lzma ; +exe test : test.cpp /lzma//lzma : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=lzma -o $config.exe') +action('-c -x c++ $lzma.h.cpp -o $lzma.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=lzma -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using lzma : : <name>mylzma <include>$(here)/lzma <search>$(here)/lzma ; +exe test : test.cpp /lzma//lzma : : <link>static <link>shared ; +""") + +t.write('lzma/lzma.h', 'lzma') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./lzma --static-lib=mylzma -o $config.exe') +action('-c -x c++ $test.cpp -I./lzma -o $test.o') +action('$test.o -L./lzma --static-lib=mylzma -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using lzma : : <name>mylzma <include>$(here)/lzma <search>$(here)/lzma ; +exe test : test.cpp /lzma//lzma : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./lzma --shared-lib=mylzma -o $config.exe') +action('-c -x c++ $test.cpp -I./lzma -o $test.o') +action('$test.o -L./lzma --shared-lib=mylzma -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - both static and shared libraries +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using lzma : : <name>mylzma <include>$(here)/lzma <search>$(here)/lzma ; +exe test : test.cpp /lzma//lzma + : <link>shared:<define>SHARED : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./lzma --static-lib=mylzma -o $config.exe') +action('$main.o -L./lzma --shared-lib=mylzma -o $config.exe') +action('-c -x c++ $test.cpp -I./lzma -o $test-static.o') +action('-c -x c++ $test.cpp -I./lzma -DSHARED -o $test-shared.o') +action('$test-static.o -L./lzma --static-lib=mylzma -o $test') +action('$test-shared.o -L./lzma --shared-lib=mylzma -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/libpng.py b/src/boost/tools/build/test/libpng.py new file mode 100755 index 00000000..3e7e5cd2 --- /dev/null +++ b/src/boost/tools/build/test/libpng.py @@ -0,0 +1,119 @@ +#!/usr/bin/python + +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Build from source +t.write("libpng/png.h", 'libpng') +t.write("libpng/png.c", 'png') + +t.write("Jamroot.jam", """ +path-constant here : . ; +using libpng : : <source>$(here)/libpng ; +alias libpng : /libpng//libpng : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, ''' +source_file('png.c', 'png') +action('-c -x c -I./libpng -o $png.o $png.c') +action('--dll $png.o -o $png.so') +action('--archive $png.o -o $png.a') +''') + +t.run_build_system() +t.expect_addition('bin/standalone/libpng/mock/debug/png.dll') +t.expect_addition('bin/standalone/libpng/mock/debug/link-static/png.lib') + +t.rm('libpng') + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('png.h.cpp', '#include <png.h>') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libpng ; +exe test : test.cpp /libpng//libpng : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=png -o $config.exe') +action('-c -x c++ $png.h.cpp -o $png.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=png -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libpng ; +exe test : test.cpp /libpng//libpng : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=png -o $config.exe') +action('-c -x c++ $png.h.cpp -o $png.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=png -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libpng : : <name>mylibpng <include>$(here)/libpng <search>$(here)/libpng ; +exe test : test.cpp /libpng//libpng : : <link>static <link>shared ; +""") + +t.write('libpng/png.h', 'libpng') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./libpng --static-lib=mylibpng -o $config.exe') +action('-c -x c++ $test.cpp -I./libpng -o $test.o') +action('$test.o -L./libpng --static-lib=mylibpng -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libpng : : <name>mylibpng <include>$(here)/libpng <search>$(here)/libpng ; +exe test : test.cpp /libpng//libpng : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./libpng --shared-lib=mylibpng -o $config.exe') +action('-c -x c++ $test.cpp -I./libpng -o $test.o') +action('$test.o -L./libpng --shared-lib=mylibpng -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/library_chain.py b/src/boost/tools/build/test/library_chain.py new file mode 100644 index 00000000..8ac21159 --- /dev/null +++ b/src/boost/tools/build/test/library_chain.py @@ -0,0 +1,152 @@ +#!/usr/bin/python + +# Copyright 2003, 2004, 2005, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that a chain of libraries works ok, no matter if we use static or shared +# linking. + +import BoostBuild +import os +import string +import sys + +t = BoostBuild.Tester(use_test_config=False) + +# Stage the binary, so that it will be relinked without hardcode-dll-paths. +# That will check that we pass correct -rpath-link, even if not passing -rpath. +t.write("jamfile.jam", """\ +stage dist : main ; +exe main : main.cpp b ; +""") + +t.write("main.cpp", """\ +void foo(); +int main() { foo(); } +""") + +t.write("jamroot.jam", "") + +t.write("a/a.cpp", """\ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +gee() {} +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +geek() {} +""") + +t.write("a/jamfile.jam", "lib a : a.cpp ;") + +t.write("b/b.cpp", """\ +void geek(); +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +foo() { geek(); } +""") + +t.write("b/jamfile.jam", "lib b : b.cpp ../a//a ;") + +t.run_build_system(["-d2"], stderr=None) +t.expect_addition("bin/$toolset/debug*/main.exe") +t.rm(["bin", "a/bin", "b/bin"]) + +t.run_build_system(["link=static"]) +t.expect_addition("bin/$toolset/debug/link-static*/main.exe") +t.rm(["bin", "a/bin", "b/bin"]) + + +# Check that <library> works for static linking. +t.write("b/jamfile.jam", "lib b : b.cpp : <library>../a//a ;") + +t.run_build_system(["link=static"]) +t.expect_addition("bin/$toolset/debug/link-static*/main.exe") + +t.rm(["bin", "a/bin", "b/bin"]) + +t.write("b/jamfile.jam", "lib b : b.cpp ../a//a/<link>shared : <link>static ;") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/main.exe") + +t.rm(["bin", "a/bin", "b/bin"]) + + +# Test that putting a library in sources of a searched library works. +t.write("jamfile.jam", """\ +exe main : main.cpp png ; +lib png : z : <name>png ; +lib z : : <name>zzz ; +""") + +t.run_build_system(["-a", "-d+2"], status=None, stderr=None) +# Try to find the "zzz" string either in response file (for Windows compilers), +# or in the standard output. +rsp = t.adjust_names("bin/$toolset/debug*/main.exe.rsp")[0] +if os.path.exists(rsp) and ( open(rsp).read().find("zzz") != -1 ): + pass +elif t.stdout().find("zzz") != -1: + pass +else: + t.fail_test(1) + +# Test main -> libb -> liba chain in the case where liba is a file and not a +# Boost.Build target. +t.rm(".") + +t.write("jamroot.jam", "") +t.write("a/jamfile.jam", """\ +lib a : a.cpp ; +install dist : a ; +""") + +t.write("a/a.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +#endif +void a() {} +""") + +t.run_build_system(subdir="a") +t.expect_addition("a/dist/a.dll") + +if sys.platform == 'win32': + # This is a Windows import library. + file = t.adjust_name("a.implib") +else: + file = t.adjust_name("a.dll") + +t.write("b/jamfile.jam", "lib b : b.cpp ../a/dist/%s ;" % file) + +t.write("b/b.cpp", """\ +#if defined(_WIN32) +__declspec(dllimport) +#endif +void a(); +#if defined(_WIN32) +__declspec(dllexport) +#endif +void b() { a(); } +""") + +t.write("jamroot.jam", "exe main : main.cpp b//b ;") + +t.write("main.cpp", """\ +#if defined(_WIN32) +__declspec(dllimport) +#endif +void b(); +int main() { b(); } +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/main.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/library_order.py b/src/boost/tools/build/test/library_order.py new file mode 100644 index 00000000..4b0585e0 --- /dev/null +++ b/src/boost/tools/build/test/library_order.py @@ -0,0 +1,94 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that on compilers sensitive to library order on linker's command line, +# we generate the correct order. + +import BoostBuild + + +t = BoostBuild.Tester(use_test_config=False) + +t.write("main.cpp", """\ +void a(); +int main() { a(); } +""") + +t.write("a.cpp", """\ +void b(); +void a() { b(); } +""") + +t.write("b.cpp", """\ +void c(); +void b() { c(); } +""") + +t.write("c.cpp", """\ +void d(); +void c() { d(); } +""") + +t.write("d.cpp", """\ +void d() {} +""") + +# The order of libraries in 'main' is crafted so that we get an error unless we +# do something about the order ourselves. +t.write("jamroot.jam", """\ +exe main : main.cpp libd libc libb liba ; +lib libd : d.cpp ; +lib libc : c.cpp : <link>static <use>libd ; +lib libb : b.cpp : <use>libc ; +lib liba : a.cpp : <use>libb ; +""") + +t.run_build_system(["-d2"]) +t.expect_addition("bin/$toolset/debug*/main.exe") + + +# Test the order between searched libraries. +t.write("jamroot.jam", """\ +exe main : main.cpp png z ; +lib png : z : <name>png ; +lib z : : <name>zzz ; +""") + +t.run_build_system(["-a", "-n", "-d+2"]) +t.fail_test(t.stdout().find("png") > t.stdout().find("zzz")) + +t.write("jamroot.jam", """\ +exe main : main.cpp png z ; +lib png : : <name>png ; +lib z : png : <name>zzz ; +""") + +t.run_build_system(["-a", "-n", "-d+2"]) +t.fail_test(t.stdout().find("png") < t.stdout().find("zzz")) + + +# Test the order between prebuilt libraries. +t.write("first.a", "") +t.write("second.a", "") +t.write("jamroot.jam", """\ +exe main : main.cpp first second ; +lib first : second : <file>first.a ; +lib second : : <file>second.a ; +""") + +t.run_build_system(["-a", "-n", "-d+2"]) +t.fail_test(t.stdout().find("first") > t.stdout().find("second")) + +t.write("jamroot.jam", """ +exe main : main.cpp first second ; +lib first : : <file>first.a ; +lib second : first : <file>second.a ; +""") + +t.run_build_system(["-a", "-n", "-d+2"]) +t.fail_test(t.stdout().find("first") < t.stdout().find("second")) + +t.cleanup() diff --git a/src/boost/tools/build/test/library_property.py b/src/boost/tools/build/test/library_property.py new file mode 100644 index 00000000..6dc57144 --- /dev/null +++ b/src/boost/tools/build/test/library_property.py @@ -0,0 +1,56 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that the <library> property has no effect on "obj" targets. Previously, +# it affected all targets, so +# +# project : requirements <library>foo ; +# exe a : a.cpp helper ; +# obj helper : helper.cpp : <optimization>off ; +# +# caused 'foo' to be built with and without optimization. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +project : requirements <library>lib//x ; +exe a : a.cpp foo ; +obj foo : foo.cpp : <variant>release ; +""") + +t.write("a.cpp", """ +void aux(); +int main() { aux(); } +""") + +t.write("foo.cpp", """ +void gee(); +void aux() { gee(); } +""") + +t.write("lib/x.cpp", """ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +gee() {} +""") + +t.write("lib/jamfile.jam", """ +lib x : x.cpp ; +""") + +t.write("lib/jamroot.jam", """ +""") + + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") +t.expect_nothing("lib/bin/$toolset/release/x.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/libtiff.py b/src/boost/tools/build/test/libtiff.py new file mode 100755 index 00000000..cb0d07b0 --- /dev/null +++ b/src/boost/tools/build/test/libtiff.py @@ -0,0 +1,119 @@ +#!/usr/bin/python + +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Build from source +t.write("libtiff/tiff.h", 'libtiff') +t.write("libtiff/tiff.c", 'tiff') + +t.write("Jamroot.jam", """ +path-constant here : . ; +using libtiff : : <source>$(here)/libtiff ; +alias libtiff : /libtiff//libtiff : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, ''' +source_file('tiff.c', 'tiff') +action('-c -x c -I./libtiff -o $tiff.o $tiff.c') +action('--dll $tiff.o -o $tiff.so') +action('--archive $tiff.o -o $tiff.a') +''') + +t.run_build_system() +t.expect_addition('bin/standalone/libtiff/mock/debug/tiff.dll') +t.expect_addition('bin/standalone/libtiff/mock/debug/link-static/tiff.lib') + +t.rm('libtiff') + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('tiff.h.cpp', '#include <tiff.h>') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libtiff ; +exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=tiff -o $config.exe') +action('-c -x c++ $tiff.h.cpp -o $tiff.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=tiff -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libtiff ; +exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=tiff -o $config.exe') +action('-c -x c++ $tiff.h.cpp -o $tiff.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=tiff -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libtiff : : <name>mylibtiff <include>$(here)/libtiff <search>$(here)/libtiff ; +exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ; +""") + +t.write('libtiff/tiff.h', 'libtiff') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./libtiff --static-lib=mylibtiff -o $config.exe') +action('-c -x c++ $test.cpp -I./libtiff -o $test.o') +action('$test.o -L./libtiff --static-lib=mylibtiff -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using libtiff : : <name>mylibtiff <include>$(here)/libtiff <search>$(here)/libtiff ; +exe test : test.cpp /libtiff//libtiff : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./libtiff --shared-lib=mylibtiff -o $config.exe') +action('-c -x c++ $test.cpp -I./libtiff -o $test.o') +action('$test.o -L./libtiff --shared-lib=mylibtiff -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/libzstd.py b/src/boost/tools/build/test/libzstd.py new file mode 100755 index 00000000..c582c6ad --- /dev/null +++ b/src/boost/tools/build/test/libzstd.py @@ -0,0 +1,118 @@ +#!/usr/bin/python + +# Copy-paste-modify from zlib.py +# Copyright (C) 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import MockToolset + +t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0) + +MockToolset.create(t) + +# Generic definitions that aren't configuration specific +common_stuff = ''' +source_file('test.cpp', 'test.cpp') +source_file('main.cpp', 'int main() {}') +source_file('zstd.h.cpp', '#include <zstd.h>\\n') +action('-c -x c++ $main.cpp -o $main.o') +''' +t.write('test.cpp', 'test.cpp') + +# Default initialization - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zstd ; +exe test : test.cpp /zstd//zstd : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --static-lib=zstd -o $config.exe') +action('-c -x c++ $zstd.h.cpp -o $zstd.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --static-lib=zstd -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Default initialization - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zstd ; +exe test : test.cpp /zstd//zstd : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o --shared-lib=zstd -o $config.exe') +action('-c -x c++ $zstd.h.cpp -o $zstd.h.o') +action('-c -x c++ $test.cpp -o $test.o') +action('$test.o --shared-lib=zstd -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - static library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zstd : : <name>myzstd <include>$(here)/zstd <search>$(here)/zstd ; +exe test : test.cpp /zstd//zstd : : <link>static <link>shared ; +""") + +t.write('zstd/zstd.h', 'zstd') + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./zstd --static-lib=myzstd -o $config.exe') +action('-c -x c++ $test.cpp -I./zstd -o $test.o') +action('$test.o -L./zstd --static-lib=myzstd -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - shared library +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zstd : : <name>myzstd <include>$(here)/zstd <search>$(here)/zstd ; +exe test : test.cpp /zstd//zstd : : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./zstd --shared-lib=myzstd -o $config.exe') +action('-c -x c++ $test.cpp -I./zstd -o $test.o') +action('$test.o -L./zstd --shared-lib=myzstd -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +# Initialization in explicit location - both static and shared libraries +t.rm('bin') +t.write("Jamroot.jam", """ +path-constant here : . ; +using zstd : : <name>myzstd <include>$(here)/zstd <search>$(here)/zstd ; +exe test : test.cpp /zstd//zstd + : <link>shared:<define>SHARED : <link>static <link>shared ; +""") + +MockToolset.set_expected(t, common_stuff + ''' +action('$main.o -L./zstd --static-lib=myzstd -o $config.exe') +action('$main.o -L./zstd --shared-lib=myzstd -o $config.exe') +action('-c -x c++ $test.cpp -I./zstd -o $test-static.o') +action('-c -x c++ $test.cpp -I./zstd -DSHARED -o $test-shared.o') +action('$test-static.o -L./zstd --static-lib=myzstd -o $test') +action('$test-shared.o -L./zstd --shared-lib=myzstd -o $test') +''') +t.run_build_system() +t.expect_addition('bin/mock/debug/test.exe') +t.expect_addition('bin/mock/debug/link-static/test.exe') + +t.cleanup() diff --git a/src/boost/tools/build/test/link.py b/src/boost/tools/build/test/link.py new file mode 100755 index 00000000..e0524ef0 --- /dev/null +++ b/src/boost/tools/build/test/link.py @@ -0,0 +1,350 @@ +#!/usr/bin/python + +# Copyright 2014-2015 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tests the link-directory rule used to create the +# common boost/ directory in the new git layout. + +import BoostBuild + +def ignore_config(t): + """These files are created by the configuration logic in link.jam + They may or may not exist, depending on the system.""" + t.ignore("bin/symlink/test-hardlink") + t.ignore("bin/test-hardlink-source") + t.ignore("bin/test-symlink") + t.ignore("bin/test-symlink-source") + +def test_basic(): + """Test creation of a single link""" + t = BoostBuild.Tester() + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + """) + + t.write("src/dir1/include/file1.h", "file1") + + t.run_build_system() + + t.expect_addition("include/file1.h") + t.expect_content("include/file1.h", "file1") + ignore_config(t) + t.expect_nothing_more() + t.cleanup() + +def test_merge_two(): + """Test merging two directories""" + t = BoostBuild.Tester() + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + """) + + t.write("src/dir1/include/file1.h", "file1") + t.write("src/dir2/include/file2.h", "file2") + + t.run_build_system() + + t.expect_addition("include/file1.h") + t.expect_content("include/file1.h", "file1") + t.expect_addition("include/file2.h") + t.expect_content("include/file2.h", "file2") + ignore_config(t) + t.expect_nothing_more() + t.cleanup() + +def test_merge_existing(group1, group2): + """Test adding a link when a different symlink already exists""" + t = BoostBuild.Tester() + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + """) + + t.write("src/dir1/include/file1.h", "file1") + t.write("src/dir2/include/file2.h", "file2") + + t.run_build_system(group1) + + if "dir1-link" in group1: + t.expect_addition("include/file1.h") + t.expect_content("include/file1.h", "file1") + if "dir2-link" in group1: + t.expect_addition("include/file2.h") + t.expect_content("include/file2.h", "file2") + ignore_config(t) + t.expect_nothing_more() + + t.run_build_system(group2) + + if "dir1-link" in group2: + if "dir1-link" not in group1: + t.expect_addition("include/file1.h") + else: + # When a directory is split the link needs to be recreated. + # On Windows, the test system checks the mod time of the + # link rather than the link target, so this may be seen as + # an update. + t.ignore_touch("include/file1.h") + t.expect_content("include/file1.h", "file1") + else: + t.ignore_removal("include/file1.h") + + if "dir2-link" in group2: + if "dir2-link" not in group1: + t.expect_addition("include/file2.h") + else: + t.ignore_touch("include/file2.h") + t.expect_content("include/file2.h", "file2") + else: + t.ignore_removal("include/file2.h") + ignore_config(t) + t.expect_nothing_more() + + t.cleanup() + +def test_merge_existing_all(): + test_merge_existing(["dir1-link"], ["dir2-link"]) + test_merge_existing(["dir2-link"], ["dir1-link"]) + test_merge_existing(["dir1-link"], ["dir1-link", "dir2-link"]) + test_merge_existing(["dir2-link"], ["dir1-link", "dir2-link"]) + +def test_merge_recursive(): + "Test merging several directories including common prefixes" + t = BoostBuild.Tester() + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + link-directory dir3-link : src/dir3/include : <location>. ; + """) + + t.write("src/dir1/include/file1.h", "file1") + t.write("src/dir2/include/file2.h", "file2") + t.write("src/dir2/include/nested/file3.h", "file3") + t.write("src/dir3/include/nested/file4.h", "file4") + + t.run_build_system() + + t.expect_addition("include/file1.h") + t.expect_content("include/file1.h", "file1") + t.expect_addition("include/file2.h") + t.expect_content("include/file2.h", "file2") + t.expect_addition("include/nested/file3.h") + t.expect_content("include/nested/file3.h", "file3") + t.expect_addition("include/nested/file4.h") + t.expect_content("include/nested/file4.h", "file4") + ignore_config(t) + t.expect_nothing_more() + + t.cleanup() + +def test_merge_recursive_existing(group1, group2): + "Test merging several directories including common prefixes." + t = BoostBuild.Tester() + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + link-directory dir3-link : src/dir3/include : <location>. ; + link-directory dir4-link : src/dir4/include : <location>. ; + link-directory dir5-link : src/dir5/include : <location>. ; + """) + + t.write("src/dir1/include/file1.h", "file1") + t.write("src/dir2/include/nested/file2.h", "file2") + t.write("src/dir3/include/nested/file3.h", "file3") + t.write("src/dir4/include/nested/xxx/yyy/file4.h", "file4") + t.write("src/dir5/include/nested/xxx/yyy/file5.h", "file5") + + t.run_build_system(group1) + t.run_build_system(group2 + ["-d+12"]) + + def check_file(target, file): + if target in group2: + if target in group1: + t.ignore_touch(file) + else: + t.expect_addition(file) + + check_file("dir1-link", "include/file1.h") + check_file("dir2-link", "include/nested/file2.h") + check_file("dir3-link", "include/nested/file3.h") + check_file("dir4-link", "include/nested/xxx/yyy/file4.h") + check_file("dir5-link", "include/nested/xxx/yyy/file5.h") + ignore_config(t) + t.expect_nothing_more() + + t.cleanup() + +def test_merge_recursive_existing_all(): + # These should create a link + test_merge_recursive_existing(["dir2-link"], ["dir2-link", "dir1-link"]) + test_merge_recursive_existing(["dir2-link"], ["dir1-link", "dir2-link"]) + # These should create a directory + test_merge_recursive_existing(["dir2-link"], ["dir2-link", "dir3-link"]) + test_merge_recursive_existing(["dir2-link"], ["dir3-link", "dir2-link"]) + # It should work even if we have to create many intermediate subdirectories + test_merge_recursive_existing(["dir4-link"], ["dir4-link", "dir5-link"]) + test_merge_recursive_existing(["dir4-link"], ["dir5-link", "dir4-link"]) + +def test_include_scan(): + """Make sure that the #include scanner finds the headers""" + t = BoostBuild.Tester() + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + obj test : test.cpp : + <include>include + <implicit-dependency>dir1-link + <implicit-dependency>dir2-link ; + """) + + t.write("src/dir1/include/file1.h", "#include <file2.h>\n") + t.write("src/dir2/include/file2.h", "int f();\n") + t.write("test.cpp", """\ + #include <file1.h> + int main() { f(); } + """); + + t.run_build_system(["test"]) + + t.expect_addition("bin/$toolset/debug*/test.obj") + + t.run_build_system() + t.expect_nothing_more() + + t.cleanup() + +def test_include_scan_merge_existing(): + """Make sure that files are replaced if needed when merging in + a new directory""" + t = BoostBuild.Tester() + + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + obj test : test.cpp : + <include>include + <implicit-dependency>dir1-link + <implicit-dependency>dir2-link ; + """) + + t.write("src/dir1/include/file1.h", "int f();") + t.write("src/dir2/include/file2.h", "#include <file1.h>") + t.write("test.cpp", """\ + #include <file2.h> + int main() { f(); } + """) + + t.run_build_system(["dir2-link"]) + + t.run_build_system(["test"]) + t.expect_addition("include/file1.h") + t.expect_addition("bin/$toolset/debug*/test.obj") + t.ignore_touch("include/file2.h") + t.expect_nothing_more() + + t.cleanup() + +def test_update_file_link(params1, params2): + """Tests the behavior of updates when changing the link mode. + The link needs to be updated iff the original was a copy.""" + t = BoostBuild.Tester() + + t.write("jamroot.jam", """\ + import link ; + import project ; + import property-set ; + import modules ; + + if --no-symlinks in [ modules.peek : ARGV ] + { + modules.poke link : .can-symlink : false ; + } + + if --no-hardlinks in [ modules.peek : ARGV ] + { + modules.poke link : .can-hardlink : false ; + } + + .project = [ project.current ] ; + .has-files = [ glob include/file1.h ] ; + + rule can-link ( properties * ) { + if ( ! [ link.can-symlink $(.project) ] ) && + ( ! [ link.can-hardlink $(.project) ] ) + { + ECHO links unsupported ; + } + } + + # Use two directories so that we link to individual files. + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + alias check-linking : : <conditional>@can-link ; + """) + t.write("src/dir1/include/file1.h", "file1") + t.write("src/dir2/include/file2.h", "file2") + + t.run_build_system(params1) + ignore_config(t) + t.expect_addition("include/file1.h") + t.expect_addition("include/file2.h") + t.expect_nothing_more() + + using_links = "links unsupported" not in t.stdout() + + t.touch("src/dir1/include/file1.h") + + t.run_build_system(params2) + if not using_links: t.expect_touch("include/file1.h") + ignore_config(t) + t.expect_nothing_more() + + t.cleanup() + +def test_update_file_link_all(): + """Test all nine possible combinations of two runs.""" + possible_args = [[], ["--no-symlinks"], ["--no-symlinks", "--no-hardlinks"]] + for arg1 in possible_args: + for arg2 in possible_args: + test_update_file_link(arg1, arg2) + +def test_error_duplicate(): + """Test that linking a single file from + multiple sources causes a hard error.""" + t = BoostBuild.Tester() + + t.write("jamroot.jam", """\ + import link ; + link-directory dir1-link : src/dir1/include : <location>. ; + link-directory dir2-link : src/dir2/include : <location>. ; + """) + + t.write("src/dir1/include/file1.h", "file1") + t.write("src/dir2/include/file1.h", "file2") + + t.run_build_system(status=1) + t.expect_output_lines( + ["error: Cannot create link include/file1.h to src/dir2/include/file1.h.", + "error: Link previously defined to another file, src/dir1/include/file1.h."]) + + t.cleanup() + +test_basic() +test_merge_two() +test_merge_existing_all() +test_merge_recursive() +test_merge_recursive_existing_all() +test_include_scan() +test_include_scan_merge_existing() +test_update_file_link_all() +test_error_duplicate() diff --git a/src/boost/tools/build/test/load_dir.py b/src/boost/tools/build/test/load_dir.py new file mode 100644 index 00000000..1b082b1c --- /dev/null +++ b/src/boost/tools/build/test/load_dir.py @@ -0,0 +1,84 @@ +#!/usr/bin/python + +""" +Traverses a directory and output the code that would create the same directory +structure during testing. Assumes that the instance of Tester is called 't'. +""" + +from __future__ import print_function + +import sys +import os +import stat +import string + +def usage(): + print("usage: load_dir.py directory") + + +def remove_first_component(path): + result = [path] + while 1: + s = os.path.split(result[0]) + if not s[0]: + break + result[:1] = list(s) + return os.path.join(*result[1:]) + + +def create_file(arg, dirname, fnames): + for n in fnames: + path = os.path.join(dirname, n) + if not os.path.isdir(path): + print("t.write(\"%s\", \"\"\"" % (remove_first_component(path),),) + f = open(path, "r") + for l in f: + print(l) + print('\n""")\n') + + +header = """#!/usr/bin/python + +# Copyright (C) FILL SOMETHING HERE 2005. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester() +""" + +footer = """ + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/FILL_SOME_HERE.exe") + +t.cleanup() +""" + + +def main(): + if len(sys.argv) != 2: + usage() + else: + path = sys.argv[1] + + if not os.access(path, os.F_OK): + print("Path '%s' does not exist" % (path,)) + sys.exit(1) + + if not os.path.isdir(path): + print("Path '%s' is not a directory" % (path,)) + + print(header) + + for root, _, files in os.walk(path): + create_file(None, root, files) + + print(footer) + + +if __name__ == '__main__': + main() diff --git a/src/boost/tools/build/test/load_order.py b/src/boost/tools/build/test/load_order.py new file mode 100644 index 00000000..6e005502 --- /dev/null +++ b/src/boost/tools/build/test/load_order.py @@ -0,0 +1,71 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that we load parent projects before loading children. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """\ +use-project /child : child ; +ECHO "Setting parent requirements" ; +project : requirements <define>PASS_THE_TEST ; +alias x : child//main ; +""") + +t.write("child/jamfile.jam", """\ +ECHO "Setting child requirements" ; +project /child ; +exe main : main.cpp ; +""") + +t.write("child/main.cpp", """\ +#if defined(PASS_THE_TEST) +int main() {} +#endif +""") + +t.run_build_system() + +t.expect_addition("child/bin/$toolset/debug*/main.exe") +t.fail_test(t.stdout().find("Setting child requirements") < t.stdout().find( + "Setting parent requirements")) + + +# Regression test: parent requirements were ignored in some cases. +t.rm(".") +t.write("jamroot.jam", "build-project src ;") +t.write("src/jamfile.jam", "project : requirements <define>EVERYTHING_OK ;") +t.write("src/app/jamfile.jam", "exe test : test.cpp ;") +t.write("src/app/test.cpp", """\ +#ifdef EVERYTHING_OK +int main() {} +#endif +""") + +t.run_build_system(subdir="src/app") +t.expect_addition("src/app/bin/$toolset/debug*/test.exe") + + +# child/child2 used to be loaded before child +t.rm(".") +t.write("jamroot.jam", """\ +use-project /child/child2 : child/child2 ; +rule parent-rule ( ) +{ + ECHO "Running parent-rule" ; +} +""") +t.write("child/jamfile.jam", "") +t.write("child/child1/jamfile.jam", "") +t.write("child/child2/jamfile.jam", "parent-rule ;") + +t.run_build_system(subdir="child/child1") +t.expect_output_lines("Running parent-rule") + +t.cleanup() diff --git a/src/boost/tools/build/test/loop.py b/src/boost/tools/build/test/loop.py new file mode 100644 index 00000000..ffb99181 --- /dev/null +++ b/src/boost/tools/build/test/loop.py @@ -0,0 +1,24 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import string + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """\ +lib main : main.cpp l ; +lib l : l.cpp main ; +""") + +t.write("main.cpp", "") +t.write("l.cpp", "") + +t.run_build_system(["--no-error-backtrace"], status=1) +t.fail_test(t.stdout().find( + "error: Recursion in main target references") == -1) + +t.cleanup() diff --git a/src/boost/tools/build/test/make_rule.py b/src/boost/tools/build/test/make_rule.py new file mode 100644 index 00000000..ad8fd42f --- /dev/null +++ b/src/boost/tools/build/test/make_rule.py @@ -0,0 +1,54 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2003, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'make' rule. + +import BoostBuild +import string + +t = BoostBuild.Tester(pass_toolset=1) + +t.write("jamroot.jam", """\ +import feature ; +feature.feature test_feature : : free ; + +import toolset ; +toolset.flags creator STRING : <test_feature> ; + +actions creator +{ + echo $(STRING) > $(<) +} + +make foo.bar : : creator : <test_feature>12345678 ; +""") + +t.run_build_system() +t.expect_addition("bin/foo.bar") +t.fail_test(t.read("bin/foo.bar").find("12345678") == -1) + + +# Regression test. Make sure that if a main target is requested two times, and +# build requests differ only in incidental properties, the main target is +# created only once. The bug was discovered by Kirill Lapshin. +t.write("jamroot.jam", """\ +exe a : dir//hello1.cpp ; +exe b : dir//hello1.cpp/<hardcode-dll-paths>true ; +""") + +t.write("dir/jamfile.jam", """\ +import common ; +make hello1.cpp : hello.cpp : common.copy ; +""") + +t.write("dir/hello.cpp", "int main() {}\n") + +# Show only action names. +t.run_build_system(["-d1", "-n"]) +t.fail_test(t.stdout().count("copy") != 1) + +t.cleanup() diff --git a/src/boost/tools/build/test/message.py b/src/boost/tools/build/test/message.py new file mode 100755 index 00000000..30edced4 --- /dev/null +++ b/src/boost/tools/build/test/message.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2003. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test for the regression testing framework. + +import BoostBuild + +# Create a temporary working directory. +t = BoostBuild.Tester(["-d0"], use_test_config=False) + +t.write("Jamroot.jam", """ +project + : + : usage-requirements <define>TEST=1 + : default-build <link>static +; +message hello : "Hello World!" ; +alias hello : : <link>shared ; +obj test : test.cpp hello : <link>static ; +""") + +t.write("test.cpp", """ +#ifndef TEST +#error TEST not defined +#endif +""") + +t.run_build_system(["test"], stdout="""Hello World! +""") + +t.expect_addition("bin/$toolset/link-static*/test.obj") +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/module_actions.py b/src/boost/tools/build/test/module_actions.py new file mode 100644 index 00000000..33c56352 --- /dev/null +++ b/src/boost/tools/build/test/module_actions.py @@ -0,0 +1,105 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2006 Rene Rivera +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Demonstration that module variables have the correct effect in actions. + +import BoostBuild +import os +import re + +t = BoostBuild.Tester(["-d+1"], pass_toolset=0) + +t.write("boost-build.jam", "boost-build . ;") +t.write("bootstrap.jam", """\ +# Top-level rule causing a target to be built by invoking the specified action. +rule make ( target : sources * : act ) +{ + DEPENDS all : $(target) ; + DEPENDS $(target) : $(sources) ; + $(act) $(target) : $(sources) ; +} + +X1 = X1-global ; +X2 = X2-global ; +X3 = X3-global ; + +module A +{ + X1 = X1-A ; + + rule act ( target ) + { + NOTFILE $(target) ; + ALWAYS $(target) ; + } + + actions act { echo A.act $(<): $(X1) $(X2) $(X3) } + + make t1 : : A.act ; + make t2 : : A.act ; + make t3 : : A.act ; +} + +module B +{ + X2 = X2-B ; + + actions act { echo B.act $(<): $(X1) $(X2) $(X3) } + + make t1 : : B.act ; + make t2 : : B.act ; + make t3 : : B.act ; +} + +actions act { echo act $(<): $(X1) $(X2) $(X3) } + +make t1 : : act ; +make t2 : : act ; +make t3 : : act ; + +X1 on t1 = X1-t1 ; +X2 on t2 = X2-t2 ; +X3 on t3 = X3-t3 ; + +DEPENDS all : t1 t2 t3 ; +""") + +expected_lines = [ + "...found 4 targets...", + "...updating 3 targets...", + "A.act t1", + "A.act t1: X1-t1 ", + "B.act t1", + "B.act t1: X1-t1 X2-B ", + "act t1", + "act t1: X1-t1 X2-global X3-global ", + "A.act t2", + "A.act t2: X1-A X2-t2 ", + "B.act t2", + "B.act t2: X2-t2 ", + "act t2", + "act t2: X1-global X2-t2 X3-global ", + "A.act t3", + "A.act t3: X1-A X3-t3 ", + "B.act t3", + "B.act t3: X2-B X3-t3 ", + "act t3", + "act t3: X1-global X2-global X3-t3 ", + "...updated 3 targets...", + ""] + +# Accommodate for the fact that on Unixes, a call to 'echo 1 2 3 ' +# produces '1 2 3' (note the spacing). +if os.name != 'nt': + expected_lines = [re.sub(" +", " ", x.rstrip()) for x in expected_lines] + +t.run_build_system() +t.expect_output_lines(expected_lines) +t.expect_nothing_more() +t.cleanup() diff --git a/src/boost/tools/build/test/ndebug.py b/src/boost/tools/build/test/ndebug.py new file mode 100644 index 00000000..87fbc6c6 --- /dev/null +++ b/src/boost/tools/build/test/ndebug.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that building with optimization brings NDEBUG define, and, more +# importantly, that dependency targets are built with NDEBUG as well, even if +# they are not directly requested. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "exe hello : hello.cpp lib//lib1 ;") +t.write("hello.cpp", """\ +#ifdef NDEBUG +void foo(); +int main() { foo(); } +#endif +""") +t.write("lib/jamfile.jam", "lib lib1 : lib1.cpp ;") +t.write("lib/lib1.cpp", """\ +#ifdef NDEBUG +void foo() {} +#endif +""") + +# 'release' builds should get the NDEBUG define. We use static linking to avoid +# messing with imports/exports on Windows. +t.run_build_system(["link=static", "release"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/no_type.py b/src/boost/tools/build/test/no_type.py new file mode 100644 index 00000000..0384ec60 --- /dev/null +++ b/src/boost/tools/build/test/no_type.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that we cannot specify targets of unknown type as sources. This is based +# on the fact that Unix 'ar' will happily consume just about anything. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("jamroot.jam", "static-lib a : a.foo ;") +t.write("a.foo", "") + +t.run_build_system(status=1) + +t.cleanup() diff --git a/src/boost/tools/build/test/notfile.py b/src/boost/tools/build/test/notfile.py new file mode 100644 index 00000000..eebc457b --- /dev/null +++ b/src/boost/tools/build/test/notfile.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2005. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Basic tests for the 'notfile' rule. + +import BoostBuild +import os + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """\ +import notfile ; +notfile say : "echo hi" ; +exe hello : hello.cpp ; +notfile hello_valgrind : @valgrind : hello ; +actions valgrind { valgrind $(>[1]) } +""") + +t.write("hello.cpp", """\ +#include <iostream> +int main() { std::cout << "Hello!\\n"; } +""") + +t.run_build_system(["-n", "-d+2"]) + +t.fail_test(t.stdout().find("echo hi") == -1) + +name = t.adjust_names("bin/$toolset/debug*/hello.exe")[0] +name = os.path.join(*name.split("/")) +t.expect_output_lines(" valgrind *%s " % name) + +t.cleanup() diff --git a/src/boost/tools/build/test/ordered_include.py b/src/boost/tools/build/test/ordered_include.py new file mode 100644 index 00000000..ef1d8745 --- /dev/null +++ b/src/boost/tools/build/test/ordered_include.py @@ -0,0 +1,251 @@ +#!/usr/bin/python +# +# Copyright (c) 2008 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt) or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +def test_default_order(): + tester = BoostBuild.Tester(use_test_config=False) + tester.write("jamroot.jam", """ + + import order ; + import "class" : new ; + + obj test : test.cpp : <include>b <include>a ; + """) + + tester.write("test.cpp", """ + #include <test.hpp> + int main() { f(); } + """) + + tester.write("a/test.hpp", """ + void f(); + """) + + tester.write("b/test.hpp", """ + """) + + tester.run_build_system() + + tester.expect_addition("bin/$toolset/debug*/test.obj") + + # Check that the dependencies are correct + tester.touch("a/test.hpp") + tester.run_build_system() + tester.expect_touch("bin/$toolset/debug*/test.obj") + tester.expect_nothing_more() + + tester.touch("b/test.hpp") + tester.run_build_system() + tester.expect_nothing_more() + + tester.cleanup() + +def test_default_order_mixed(): + tester = BoostBuild.Tester(use_test_config=False) + tester.write("jamroot.jam", """ + + import order ; + import "class" : new ; + + obj test : test.cpp : <include>b <include>a <include>c&&d ; + """) + + tester.write("test.cpp", """ + #include <test.hpp> + int main() { f(); } + """) + + tester.write("a/test.hpp", """ + void f(); + """) + + tester.write("b/test.hpp", """ + """) + + tester.run_build_system() + + tester.expect_addition("bin/$toolset/debug*/test.obj") + + # Check that the dependencies are correct + tester.touch("a/test.hpp") + tester.run_build_system() + tester.expect_touch("bin/$toolset/debug*/test.obj") + tester.expect_nothing_more() + + tester.touch("b/test.hpp") + tester.run_build_system() + tester.expect_nothing_more() + + tester.cleanup() + +def test_basic(): + tester = BoostBuild.Tester(use_test_config=False) + tester.write("jamroot.jam", """ + obj test : test.cpp : <include>a&&b ; + """) + + tester.write("test.cpp", """ + #include <test1.hpp> + #include <test2.hpp> + int main() {} + """) + + tester.write("a/test1.hpp", """ + """) + + tester.write("b/test2.hpp", """ + """) + + tester.run_build_system() + + tester.expect_addition("bin/$toolset/debug*/test.obj") + + # Check that the dependencies are correct + tester.touch("a/test1.hpp") + tester.run_build_system() + tester.expect_touch("bin/$toolset/debug*/test.obj") + + tester.touch("b/test2.hpp") + tester.run_build_system() + tester.expect_touch("bin/$toolset/debug*/test.obj") + + tester.cleanup() + +def test_order1(): + t = BoostBuild.Tester(use_test_config=False) + t.write("jamroot.jam", """ + obj test : test.cpp : <include>a&&b ; + """) + t.write("test.cpp", """ + #include <test.h> + int main() {} + """) + t.write("a/test.h", """ + """) + t.write("b/test.h", """ + #error should find a/test.h + """) + t.run_build_system() + + t.touch("a/test.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/test.obj") + t.expect_nothing_more() + + t.touch("b/test.h") + t.run_build_system() + t.expect_nothing_more() + + t.cleanup() + +def test_order2(): + t = BoostBuild.Tester(use_test_config=False) + t.write("jamroot.jam", """ + obj test : test.cpp : <include>b&&a ; + """) + t.write("test.cpp", """ + #include <test.h> + int main() {} + """) + t.write("a/test.h", """ + #error should find b/test.h + """) + t.write("b/test.h", """ + """) + t.run_build_system() + + t.touch("a/test.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("b/test.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/test.obj") + t.expect_nothing_more() + + t.cleanup() + +def test_order_graph(): + t = BoostBuild.Tester(use_test_config=False) + t.write("jamroot.jam", """ + obj test : test.cpp : + <include>b&&a + <include>c&&b + <include>a + <include>c + <include>b + <include>e&&b&&d + ; + """) + t.write("test.cpp", """ + #include <test1.h> + #include <test2.h> + #include <test3.h> + #include <test4.h> + int main() {} + """) + t.write("b/test1.h", "") + t.write("a/test1.h", "#error should find b/test1.h\n") + + t.write("c/test2.h", "") + t.write("b/test2.h", "#error should find c/test2.h\n") + + t.write("e/test3.h", "") + t.write("b/test3.h", "#error should find e/test3.h\n") + + t.write("b/test4.h", "") + t.write("d/test4.h", "#error should find b/test4.h\n") + + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/test.obj") + + t.touch("b/test1.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/test.obj") + t.expect_nothing_more() + + t.touch("a/test1.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("c/test2.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/test.obj") + t.expect_nothing_more() + + t.touch("b/test2.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("e/test3.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/test.obj") + t.expect_nothing_more() + + t.touch("b/test3.h") + t.run_build_system() + t.expect_nothing_more() + + t.touch("b/test4.h") + t.run_build_system() + t.expect_touch("bin/$toolset/debug*/test.obj") + t.expect_nothing_more() + + t.touch("d/test4.h") + t.run_build_system() + t.expect_nothing_more() + + t.cleanup() + +test_default_order() +test_default_order_mixed() +test_basic() +test_order1() +test_order2() +test_order_graph() diff --git a/src/boost/tools/build/test/ordered_properties.py b/src/boost/tools/build/test/ordered_properties.py new file mode 100644 index 00000000..6976f334 --- /dev/null +++ b/src/boost/tools/build/test/ordered_properties.py @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This checks that Boost.Build does not reorder <include> properties +# lexicographically. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("a.cpp", """ +#include <a.h> +int main() { foo(); } +""") + +t.write("jamroot.jam", """ +exe a : a.cpp : <include>d2 <include>d1 ; +""") + +t.write("d1/a.h", """ +""") + +t.write("d2/a.h", """ +inline void foo() {} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/out_of_tree.py b/src/boost/tools/build/test/out_of_tree.py new file mode 100644 index 00000000..400101e9 --- /dev/null +++ b/src/boost/tools/build/test/out_of_tree.py @@ -0,0 +1,29 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2005. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that we can build a project when the current directory is outside of +# that project tree, that is 'bjam some_dir' works. + +import BoostBuild + +# Create a temporary working directory. +t = BoostBuild.Tester(use_test_config=False) + +# Create the needed files. +t.write("p1/jamroot.jam", "exe hello : hello.cpp ;") +t.write("p1/hello.cpp", "int main() {}\n") +t.write("p2/jamroot.jam", """\ +exe hello2 : hello.cpp ; +exe hello3 : hello.cpp ; +""") +t.write("p2/hello.cpp", "int main() {}\n") + +t.run_build_system(["p1", "p2//hello3"]) +t.expect_addition("p1/bin/$toolset/debug*/hello.exe") +t.expect_addition("p2/bin/$toolset/debug*/hello3.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/package.py b/src/boost/tools/build/test/package.py new file mode 100644 index 00000000..7cc5e33c --- /dev/null +++ b/src/boost/tools/build/test/package.py @@ -0,0 +1,231 @@ +#!/usr/bin/python + +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the package module. + +import BoostBuild +import os + +def setup(): + t = BoostBuild.Tester(["p//install", "p//data"], + use_test_config=False) + + t.write("p/jamroot.jam", "") + t.write("p/jamfile.jam", """\ + import package ; + exe a : a.cpp ; + lib b : b.cpp ; + package.install install Test : + : a + : b/<link>static b/<link>shared + : a.h ; + package.install-data data : Test : a.txt ; + """) + t.write("p/a.cpp", "int main() {}") + t.write("p/b.cpp", """ + int + #ifdef _WIN32 + __declspec(dllexport) + #endif + must_export_something; + """) + t.write("p/a.h", "") + t.write("p/a.txt", "") + return t + +def test_defaults(): + t = setup() + + # Since the default install location is outside out test area, + # we don't want to actually execute the build. + t.run_build_system(["-n", "-d1"]) + + installdir = "C:/Test" if os.name == 'nt' else "/usr/local" + t.expect_output_lines([ + x.replace('/', os.sep) for x in + ["common.copy %s/bin/%s" % (installdir, t.adjust_name("a.exe")), + "common.copy %s/lib/%s" % (installdir, t.adjust_name("b.dll")), + "common.copy %s/lib/%s" % (installdir, t.adjust_name("b.lib")), + "common.copy %s/include/a.h" % installdir, + "common.copy %s/share/Test/a.txt" % installdir]]) + + t.cleanup() + +def test_prefix(): + t = setup() + # An explicit --prefix on the command should override all of these: + t.write("project-config.jam", """ + option.set prefix : bad ; + option.set bindir : bad/bin ; + option.set libdir : bad/lib ; + option.set includedir : bad/include ; + option.set datarootdir : bad/share ; + """) + + t.run_build_system(["--prefix=installdir"]) + t.expect_addition("installdir/bin/a.exe") + t.expect_addition("installdir/lib/b.dll") + t.expect_addition("installdir/lib/b.lib") + t.expect_addition("installdir/include/a.h") + t.expect_addition("installdir/share/Test/a.txt") + + t.cleanup() + +def test_subdirs(): + t = setup() + # Command line options override config files + t.write("project-config.jam", """ + option.set prefix : bad ; + option.set bindir : bad/bin ; + option.set libdir : bad/lib ; + option.set includedir : bad/include ; + option.set datarootdir : bad/share ; + """) + + t.run_build_system(["--libdir=installdir/lib64", + "--bindir=installdir/binx", + "--includedir=installdir/includex", + "--datarootdir=installdir/sharex"]) + t.expect_addition("installdir/binx/a.exe") + t.expect_addition("installdir/lib64/b.dll") + t.expect_addition("installdir/lib64/b.lib") + t.expect_addition("installdir/includex/a.h") + t.expect_addition("installdir/sharex/Test/a.txt") + + t.cleanup() + +def test_subdirs_with_prefix(): + t = setup() + # Command line options override config files + t.write("project-config.jam", """ + option.set prefix : bad ; + option.set bindir : bad/bin ; + option.set libdir : bad/lib ; + option.set includedir : bad/include ; + option.set datarootdir : bad/share ; + """) + + t.run_build_system(["--prefix=bad", + "--libdir=installdir/lib64", + "--bindir=installdir/binx", + "--includedir=installdir/includex", + "--datarootdir=installdir/sharex"]) + t.expect_addition("installdir/binx/a.exe") + t.expect_addition("installdir/lib64/b.dll") + t.expect_addition("installdir/lib64/b.lib") + t.expect_addition("installdir/includex/a.h") + t.expect_addition("installdir/sharex/Test/a.txt") + + t.cleanup() + +def test_prefix_config_file(): + t = setup() + # An explicit --prefix on the command should override all of these: + t.write("project-config.jam", """ + option.set prefix : installdir ; + """) + + t.run_build_system() + t.expect_addition("installdir/bin/a.exe") + t.expect_addition("installdir/lib/b.dll") + t.expect_addition("installdir/lib/b.lib") + t.expect_addition("installdir/include/a.h") + t.expect_addition("installdir/share/Test/a.txt") + + t.cleanup() + +def test_subdirs_config_file(): + t = setup() + # An explicit --prefix on the command should override all of these: + t.write("project-config.jam", """ + option.set prefix : installdir ; + option.set libdir : installdir/lib64 ; + option.set bindir : installdir/binx ; + option.set includedir : installdir/includex ; + option.set datarootdir : installdir/sharex ; + """) + + t.run_build_system() + t.expect_addition("installdir/binx/a.exe") + t.expect_addition("installdir/lib64/b.dll") + t.expect_addition("installdir/lib64/b.lib") + t.expect_addition("installdir/includex/a.h") + t.expect_addition("installdir/sharex/Test/a.txt") + + t.cleanup() + +def test_multiple(): + '''If no prefix is specified, we might use several default + install prefixes.''' + t = BoostBuild.Tester(use_test_config=False) + + t.write("p/jamroot.jam", "") + t.write("p/jamfile.jam", """\ + import package ; + exe a : a.cpp ; + lib b : b.cpp ; + package.install installx TestX : <install-default-prefix>xxx + : a + : b/<link>static b/<link>shared + : a.h ; + package.install instally TestY : <install-default-prefix>yyy + : a + : b/<link>static b/<link>shared + : a.h ; + """) + t.write("p/a.cpp", "int main() {}") + t.write("p/b.cpp", """ + int + #ifdef _WIN32 + __declspec(dllexport) + #endif + must_export_something; + """) + t.write("p/a.h", "") + t.run_build_system(["p//installx", "p//instally"]) + t.expect_addition("p/xxx/bin/a.exe") + t.expect_addition("p/xxx/lib/b.dll") + t.expect_addition("p/xxx/lib/b.lib") + t.expect_addition("p/xxx/include/a.h") + t.expect_addition("p/yyy/bin/a.exe") + t.expect_addition("p/yyy/lib/b.dll") + t.expect_addition("p/yyy/lib/b.lib") + t.expect_addition("p/yyy/include/a.h") + +def test_paths(): + t = BoostBuild.Tester(pass_toolset=False) + t.write("Jamroot.jam", """\ + import package ; + import assert ; + import os ; + if [ os.name ] = NT + { + default-prefix = "/C:/Test" ; + } + else + { + default-prefix = /usr/local ; + } + paths = [ package.paths Test ] ; + assert.result $(default-prefix) : $(paths).prefix ; + assert.result $(default-prefix)/lib : $(paths).libdir ; + assert.result $(default-prefix)/bin : $(paths).bindir ; + assert.result $(default-prefix)/include : $(paths).includedir ; + assert.result $(default-prefix)/share : $(paths).datarootdir ; + package.add-path-option bardir : bar : libdir ; + assert.result $(default-prefix)/lib/bar : $(paths).get bardir ; + """) + t.run_build_system() + t.cleanup() + +test_defaults() +test_prefix() +test_subdirs() +test_subdirs_with_prefix() +test_prefix_config_file() +test_subdirs_config_file() +test_multiple() +test_paths() diff --git a/src/boost/tools/build/test/param.py b/src/boost/tools/build/test/param.py new file mode 100644 index 00000000..14b3d7d9 --- /dev/null +++ b/src/boost/tools/build/test/param.py @@ -0,0 +1,61 @@ +#!/usr/bin/python + +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("Jamroot.jam", """\ +import param ; +import assert ; +import errors : try catch ; +rule test1 ( ) +{ + param.handle-named-params ; +} +test1 ; +rule test2 ( sources * ) +{ + param.handle-named-params sources ; + return $(sources) ; +} +assert.result : test2 ; +assert.result test1.cpp test2.cpp : test2 test1.cpp test2.cpp ; +assert.result test1.cpp test2.cpp : test2 sources test1.cpp test2.cpp ; +rule test3 ( sources * : requirements * ) +{ + param.handle-named-params sources requirements ; + return $(sources) -- $(requirements) ; +} +assert.result -- : test3 ; +assert.result -- <link>shared : test3 : <link>shared ; +assert.result test1.cpp -- <link>shared : test3 test1.cpp : <link>shared ; +assert.result test1.cpp -- <link>shared + : test3 test1.cpp : requirements <link>shared ; +assert.result test1.cpp -- <link>shared + : test3 sources test1.cpp : requirements <link>shared ; +assert.result test1.cpp -- <link>shared + : test3 requirements <link>shared : sources test1.cpp ; +assert.result -- : test3 sources ; +assert.result -- : test3 requirements ; +assert.result -- <link>shared : test3 requirements <link>shared ; +try ; +{ + test3 sources test1.cpp : sources test2.cpp ; +} +catch Parameter 'sources' passed more than once. ; +try ; +{ + test3 sources test1.cpp : <link>shared ; +} +catch "Positional arguments must appear first." ; +EXIT : 0 ; +""") + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/path_features.py b/src/boost/tools/build/test/path_features.py new file mode 100644 index 00000000..5b23150b --- /dev/null +++ b/src/boost/tools/build/test/path_features.py @@ -0,0 +1,163 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +def test_basic(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "lib a : a.cpp : <include>. ;") + t.write("a.cpp", """\ +#include <a.h> +void +# ifdef _WIN32 +__declspec(dllexport) +# endif +foo() {} +""") + t.write("a.h", "//empty file\n") + t.write("d/jamfile.jam", "exe b : b.cpp ..//a ;") + t.write("d/b.cpp", """\ +void foo(); +int main() { foo(); } +""") + t.run_build_system(subdir="d") + + # Path features with condition. + t.write("jamroot.jam", "lib a : a.cpp : <variant>debug:<include>. ;") + t.rm("bin") + t.run_build_system(subdir="d") + + + # Path features with condition in usage requirements. + t.write("jamroot.jam", """\ +lib a : a.cpp : <include>. : : <variant>debug:<include>. ; +""") + t.write("d/b.cpp", """\ +#include <a.h> +void foo(); +int main() { foo(); } +""") + t.rm("d/bin") + t.run_build_system(subdir="d") + + t.cleanup() + + +def test_absolute_paths(): + """ + Test that absolute paths inside requirements are ok. The problems + appeared only when building targets in subprojects. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "build-project x ;") + t.write("x/jamfile.jam", """\ +local pwd = [ PWD ] ; +project : requirements <include>$(pwd)/x/include ; +exe m : m.cpp : <include>$(pwd)/x/include2 ; +""") + t.write("x/m.cpp", """\ +#include <h1.hpp> +#include <h2.hpp> +int main() {} +""") + t.write("x/include/h1.hpp", "\n") + t.write("x/include2/h2.hpp", "\n") + + t.run_build_system() + t.expect_addition("x/bin/$toolset/debug*/m.exe") + + t.cleanup() + + +def test_ordered_paths(): + """Test that "&&" in path features is handled correctly.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "build-project sub ;") + t.write("sub/jamfile.jam", "exe a : a.cpp : <include>../h1&&../h2 ;") + t.write("sub/a.cpp", """\ +#include <header.h> +int main() { return OK; } +""") + t.write("h2/header.h", "int const OK = 0;\n") + t.run_build_system() + t.expect_addition("sub/bin/$toolset/debug*/a.exe") + + t.cleanup() + + +def test_paths_set_by_indirect_conditionals(): + t = BoostBuild.Tester(use_test_config=False) + + header = "child_dir/folder_to_include/some_header.h" + + t.write("jamroot.jam", """ +build-project child_dir ; +rule attach-include-parent ( properties * ) +{ + return <include>another_folder ; +} +# requirements inherited from a parent project will bind paths +# relative to the project that actually names the rule. +project : requirements <conditional>@attach-include-parent ; +""") + t.write("child_dir/jamfile.jam", """\ +import remote/remote ; + +# If we set the <include>folder_to_include property directly, it will work +obj x1 : x.cpp : <conditional>@attach-include-local ; +obj x2 : x.cpp : <conditional>@remote.attach-include-remote ; + +rule attach-include-local ( properties * ) +{ + return <include>folder_to_include ; +} +""") + t.write("child_dir/remote/remote.jam", """\ +rule attach-include-remote ( properties * ) +{ + return <include>folder_to_include ; +} +""") + t.write("child_dir/x.cpp", """\ +#include <some_header.h> +#include <header2.h> +int main() {} +""") + t.write(header, "int some_func();\n") + t.write("another_folder/header2.h", "int f2();\n") + t.write("child_dir/folder_to_include/jamfile.jam", "") + + expected_x1 = "child_dir/bin/$toolset/debug*/x1.obj" + expected_x2 = "child_dir/bin/$toolset/debug*/x2.obj" + + t.run_build_system() + t.expect_addition(expected_x1) + t.expect_addition(expected_x2) + + t.touch(header) + t.run_build_system(subdir="child_dir") + t.expect_touch(expected_x1) + t.expect_touch(expected_x2) + + t.touch(header) + t.run_build_system([".."], subdir="child_dir/folder_to_include") + t.expect_touch(expected_x1) + t.expect_touch(expected_x2) + + t.cleanup() + + +test_basic() +test_absolute_paths() +test_ordered_paths() +test_paths_set_by_indirect_conditionals() diff --git a/src/boost/tools/build/test/pch.py b/src/boost/tools/build/test/pch.py new file mode 100644 index 00000000..0b6baaf5 --- /dev/null +++ b/src/boost/tools/build/test/pch.py @@ -0,0 +1,58 @@ +#!/usr/bin/python + +# Copyright 2006 Vladimir Prus. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +from time import sleep + + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """ +import pch ; +cpp-pch pch : pch.hpp : <toolset>msvc:<source>pch.cpp <include>. ; +exe hello : hello.cpp pch : <include>. ; +""") + +t.write("pch.hpp.bad", """ +THIS WILL NOT COMPILE +""") + +# Note that pch.hpp is written after pch.hpp.bad, so its timestamp will not be +# less than timestamp of pch.hpp.bad. +sleep(1) +t.write("pch.hpp", """ +class TestClass +{ +public: + TestClass( int, int ) {} +}; +""") + +t.write("pch.cpp", """#include <pch.hpp> +""") + +t.write("hello.cpp", """#include <pch.hpp> +int main() { TestClass c(1, 2); } +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.exe") + + +# Now make the header unusable, without changing timestamp. If everything is OK, +# Boost.Build will not recreate PCH, and compiler will happily use pre-compiled +# header, not noticing that the real header is bad. + +t.copy_preserving_timestamp("pch.hpp.bad", "pch.hpp") + +t.rm("bin/$toolset/debug/hello.obj") +t.rm("bin/$toolset/debug/*/hello.obj") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/prebuilt.py b/src/boost/tools/build/test/prebuilt.py new file mode 100644 index 00000000..e67b726e --- /dev/null +++ b/src/boost/tools/build/test/prebuilt.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +# Copyright 2002, 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that we can use already built sources + +import BoostBuild + +t = BoostBuild.Tester(["debug", "release"], use_test_config=False) + +t.set_tree('prebuilt') + +t.expand_toolset("ext/jamroot.jam") +t.expand_toolset("jamroot.jam") + +# First, build the external project. +t.run_build_system(subdir="ext") + +# Then pretend that we do not have the sources for the external project, and +# can only use compiled binaries. +t.copy("ext/jamfile2.jam", "ext/jamfile.jam") +t.expand_toolset("ext/jamfile.jam") + +# Now check that we can build the main project, and that correct prebuilt file +# is picked, depending of variant. This also checks that correct includes for +# prebuilt libraries are used. +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.exe") +t.expect_addition("bin/$toolset/release*/hello.exe") + +t.rm("bin") + + +# Now test that prebuilt file specified by absolute name works too. +t.copy("ext/jamfile3.jam", "ext/jamfile.jam") +t.expand_toolset("ext/jamfile.jam") +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.exe") +t.expect_addition("bin/$toolset/release*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/prebuilt/ext/a.cpp b/src/boost/tools/build/test/prebuilt/ext/a.cpp new file mode 100644 index 00000000..c49a0415 --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/a.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// + +#ifdef _WIN32 +__declspec(dllexport) +#endif +#ifdef RELEASE +void release() {} +#else +void debug() {} +#endif diff --git a/src/boost/tools/build/test/prebuilt/ext/debug/a.h b/src/boost/tools/build/test/prebuilt/ext/debug/a.h new file mode 100644 index 00000000..31b31822 --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/debug/a.h @@ -0,0 +1,13 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// + +#ifdef _WIN32 +__declspec(dllimport) +#endif +void debug(); diff --git a/src/boost/tools/build/test/prebuilt/ext/jamfile.jam b/src/boost/tools/build/test/prebuilt/ext/jamfile.jam new file mode 100644 index 00000000..e563f0d7 --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/jamfile.jam @@ -0,0 +1,13 @@ +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +project ext + : requirements <variant>release:<define>RELEASE + ; + +lib a : a.cpp ; + +install dist : a : <variant>release:<location>release + <variant>debug:<location>debug ; diff --git a/src/boost/tools/build/test/prebuilt/ext/jamfile2.jam b/src/boost/tools/build/test/prebuilt/ext/jamfile2.jam new file mode 100644 index 00000000..6481808c --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/jamfile2.jam @@ -0,0 +1,41 @@ + +import os ; + +local dll-suffix = so ; +local prefix = "lib" ; +if [ os.name ] in NT +{ + if [ MATCH ^(gcc) : $toolset ] + { + dll-suffix = dll.a ; + prefix = lib ; + } + else + { + dll-suffix = lib ; + prefix = "" ; + } +} +else if [ os.name ] in CYGWIN +{ + dll-suffix = dll ; +} +else if [ os.name ] in MACOSX +{ + dll-suffix = dylib ; +} + +project ext ; + +lib a : + : <file>debug/$(prefix)a.$(dll-suffix) <variant>debug + : + : <include>debug + ; + +lib a : + : <file>release/$(prefix)a.$(dll-suffix) <variant>release + : + : <include>release + ; + diff --git a/src/boost/tools/build/test/prebuilt/ext/jamfile3.jam b/src/boost/tools/build/test/prebuilt/ext/jamfile3.jam new file mode 100644 index 00000000..be2257fa --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/jamfile3.jam @@ -0,0 +1,48 @@ + +# This Jamfile is the same as Jamfile2, except that +# it tries to access prebuilt targets using absolute +# paths. It used to be broken on Windows. + +import os ; + +local dll-suffix = so ; +local prefix = "lib" ; +if [ os.name ] in NT +{ + if [ MATCH ^(gcc) : $toolset ] + { + dll-suffix = dll.a ; + prefix = lib ; + } + else + { + dll-suffix = lib ; + prefix = "" ; + } +} +else if [ os.name ] in CYGWIN +{ + dll-suffix = dll ; +} +else if [ os.name ] in MACOSX +{ + dll-suffix = dylib ; +} + +project ext ; + +# Assumed bjam was invoked from the project root +local pwd = [ PWD ] ; + +lib a : + : <file>$(pwd)/ext/debug/$(prefix)a.$(dll-suffix) <variant>debug + : + : <include>debug + ; + +lib a : + : <file>$(pwd)/ext/release/$(prefix)a.$(dll-suffix) <variant>release + : + : <include>release + ; + diff --git a/src/boost/tools/build/test/prebuilt/ext/jamroot.jam b/src/boost/tools/build/test/prebuilt/ext/jamroot.jam new file mode 100644 index 00000000..c7617d5d --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/jamroot.jam @@ -0,0 +1,5 @@ +# Copyright 2002, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + diff --git a/src/boost/tools/build/test/prebuilt/ext/release/a.h b/src/boost/tools/build/test/prebuilt/ext/release/a.h new file mode 100644 index 00000000..9ab71d88 --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/ext/release/a.h @@ -0,0 +1,13 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// + +#ifdef _WIN32 +__declspec(dllimport) +#endif +void release(); diff --git a/src/boost/tools/build/test/prebuilt/hello.cpp b/src/boost/tools/build/test/prebuilt/hello.cpp new file mode 100644 index 00000000..4c1ab703 --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/hello.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// + +#include <a.h> + +int main() +{ + #ifdef RELEASE + release(); + #else + debug(); + #endif + return 0; +} diff --git a/src/boost/tools/build/test/prebuilt/jamfile.jam b/src/boost/tools/build/test/prebuilt/jamfile.jam new file mode 100644 index 00000000..18b731ae --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/jamfile.jam @@ -0,0 +1,13 @@ +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +project test + : requirements <variant>release:<define>RELEASE + ; + +use-project /ext : ext ; + +exe hello : hello.cpp /ext//a ; + diff --git a/src/boost/tools/build/test/prebuilt/jamroot.jam b/src/boost/tools/build/test/prebuilt/jamroot.jam new file mode 100644 index 00000000..f022c0d6 --- /dev/null +++ b/src/boost/tools/build/test/prebuilt/jamroot.jam @@ -0,0 +1,4 @@ +# Copyright 2002, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + diff --git a/src/boost/tools/build/test/preprocessor.py b/src/boost/tools/build/test/preprocessor.py new file mode 100755 index 00000000..715ae3e5 --- /dev/null +++ b/src/boost/tools/build/test/preprocessor.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the C/C++ preprocessor. + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("jamroot.jam", """ +project ; +preprocessed hello : hello.cpp ; +preprocessed a : a.c ; +exe hello.exe : hello a : <define>FAIL ; +""") + +t.write("hello.cpp", """ +#ifndef __cplusplus +#error "This file must be compiled as C++" +#endif +#ifdef FAIL +#error "Not preprocessed?" +#endif +extern "C" int foo(); +int main() { return foo(); } +""") + +t.write("a.c", """ +/* This will not compile unless in C mode. */ +#ifdef __cplusplus +#error "This file must be compiled as C" +#endif +#ifdef FAIL +#error "Not preprocessed?" +#endif +int foo() +{ + int new = 0; + new = (new+1)*7; + return new; +} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/hello.ii") +t.expect_addition("bin/$toolset/debug*/a.i") +t.expect_addition("bin/$toolset/debug*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/print.py b/src/boost/tools/build/test/print.py new file mode 100644 index 00000000..6579bce5 --- /dev/null +++ b/src/boost/tools/build/test/print.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# Copyright 2003 Douglas Gregor +# Copyright 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("jamroot.jam", "import gcc ;") + +t.write("jamfile.jam", """ +import print ; +print.output foo ; +print.text \\\"Something\\\" ; +DEPENDS all : foo ; +ALWAYS foo ; +""") + +t.run_build_system() +t.expect_content("foo", """\"Something\"""") + +t.write("jamfile.jam", """ +import print ; +print.output foo ; +print.text \\\n\\\"Somethingelse\\\" ; +DEPENDS all : foo ; +ALWAYS foo ; +""") + +t.run_build_system() +t.expect_content("foo", """\"Something\" +\"Somethingelse\"""") + +t.write("jamfile.jam", """ +import print ; +print.output foo ; +print.text \\\"Different\\\" : true ; +DEPENDS all : foo ; +ALWAYS foo ; +""") + +t.run_build_system() +t.expect_content("foo", """\"Different\"""") + +t.cleanup() diff --git a/src/boost/tools/build/test/project-test3/a.cpp b/src/boost/tools/build/test/project-test3/a.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/a.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test3/jamfile.jam b/src/boost/tools/build/test/project-test3/jamfile.jam new file mode 100644 index 00000000..f0796077 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/jamfile.jam @@ -0,0 +1,13 @@ +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +use-project /lib2 : lib2 ; +use-project /lib3 : lib3 ; + +make a.exe : a.obj lib//b.obj /lib2//c.obj lib2//d.obj lib2/helper//e.obj /lib3//f.obj : yfc-link ; +make a.obj : a.cpp : yfc-compile ; + +build-project lib2 ; +build-project lib ; diff --git a/src/boost/tools/build/test/project-test3/jamroot.jam b/src/boost/tools/build/test/project-test3/jamroot.jam new file mode 100644 index 00000000..d7cd490e --- /dev/null +++ b/src/boost/tools/build/test/project-test3/jamroot.jam @@ -0,0 +1,67 @@ +# Copyright 2002-2005 Vladimir Prus. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os ; +import gcc ; +import property ; +import toolset ; + +rule properties-as-path ( properties * ) +{ + local r ; + for local p in $(properties) + { + if $(p:G) != <action> + { + r += $(p) ; + } + } + return [ property.as-path + [ property.remove incidental : $(r) ] ] ; +} + +toolset.flags yfc-compile KNOWN-PROPERTIES : <toolset> <optimization> ; +toolset.flags yfc-link KNOWN-PROPERTIES : <toolset> <optimization> ; + +rule yfc-compile ( target : sources * : property-set * ) +{ + PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ; +} + +actions yfc-compile +{ + echo $(PROPERTIES) > $(<) + echo $(>) >> $(<) +} + +rule yfc-link ( target : sources * : property-set * ) +{ + PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ; +} + +actions yfc-link +{ + echo $(PROPERTIES) > $(<) + echo $(>) >> $(<) +} + +if [ os.name ] = VMS +{ + actions yfc-compile + { + PIPE WRITE SYS$OUTPUT "$(PROPERTIES)" | TYPE SYS$INPUT /OUT=$(<:W) + PIPE WRITE SYS$OUTPUT "$(>:J= ",")" | APPEND /NEW SYS$INPUT $(<:W) + } + + actions yfc-link + { + PIPE WRITE SYS$OUTPUT "$(PROPERTIES)" | TYPE SYS$INPUT /OUT=$(<:W) + OPEN /APPEND FOUT $(<:W) + WRITE FOUT "$(>:J= ",")" + CLOSE FOUT + } +} + +IMPORT $(__name__) : yfc-compile yfc-link : : yfc-compile yfc-link ; diff --git a/src/boost/tools/build/test/project-test3/lib/b.cpp b/src/boost/tools/build/test/project-test3/lib/b.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib/b.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test3/lib/jamfile.jam b/src/boost/tools/build/test/project-test3/lib/jamfile.jam new file mode 100644 index 00000000..76b0829a --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib/jamfile.jam @@ -0,0 +1,9 @@ +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +use-project /lib2 : ../lib2 ; + +make b.obj : b.cpp : yfc-compile ; +make m.exe : b.obj /lib2//c.obj : yfc-link ; diff --git a/src/boost/tools/build/test/project-test3/lib2/c.cpp b/src/boost/tools/build/test/project-test3/lib2/c.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib2/c.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test3/lib2/d.cpp b/src/boost/tools/build/test/project-test3/lib2/d.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib2/d.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test3/lib2/helper/e.cpp b/src/boost/tools/build/test/project-test3/lib2/helper/e.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib2/helper/e.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test3/lib2/helper/jamfile.jam b/src/boost/tools/build/test/project-test3/lib2/helper/jamfile.jam new file mode 100644 index 00000000..0c82f924 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib2/helper/jamfile.jam @@ -0,0 +1,9 @@ +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +project lib2/helper ; + +make e.obj : e.cpp : yfc-compile ; + diff --git a/src/boost/tools/build/test/project-test3/lib2/jamfile.jam b/src/boost/tools/build/test/project-test3/lib2/jamfile.jam new file mode 100644 index 00000000..b6b0abc4 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib2/jamfile.jam @@ -0,0 +1,11 @@ +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +project lib2 ; +use-project /lib2/helper : helper ; + +make c.obj : c.cpp : yfc-compile ; +make d.obj : d.cpp : yfc-compile ; +make l.exe : c.obj ..//a.obj : yfc-link ; diff --git a/src/boost/tools/build/test/project-test3/lib3/f.cpp b/src/boost/tools/build/test/project-test3/lib3/f.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib3/f.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test3/lib3/jamfile.jam b/src/boost/tools/build/test/project-test3/lib3/jamfile.jam new file mode 100644 index 00000000..26106299 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib3/jamfile.jam @@ -0,0 +1,47 @@ +# Copyright 2003, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This project-root.jam also serves the role of Jamfile +project lib3 ; + +use-project /lib2/helper : ../lib2/helper ; + +import os ; +import property ; + +rule properties-as-path ( properties * ) +{ + local r ; + for local p in $(properties) + { + if $(p:G) != <action> + { + r += $(p) ; + } + } + return [ property.as-path + [ property.remove incidental : $(r) ] ] ; +} + +rule mfc-compile ( target : sources * : property-set * ) +{ + PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ; +} + +actions mfc-compile +{ + echo $(PROPERTIES) > $(<) + echo $(>) >> $(<) +} + +if [ os.name ] = VMS +{ + actions mfc-compile + { + PIPE WRITE SYS$OUTPUT "$(PROPERTIES)" | TYPE SYS$INPUT /OUT=$(<:W) + PIPE WRITE SYS$OUTPUT "$(>:J= ",")" | APPEND /NEW SYS$INPUT $(<:W) + } +} + +make f.obj : f.cpp /lib2/helper//e.obj : mfc-compile ; diff --git a/src/boost/tools/build/test/project-test3/lib3/jamroot.jam b/src/boost/tools/build/test/project-test3/lib3/jamroot.jam new file mode 100644 index 00000000..971f0309 --- /dev/null +++ b/src/boost/tools/build/test/project-test3/lib3/jamroot.jam @@ -0,0 +1,5 @@ +# Copyright 2002 Rene Rivera +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + diff --git a/src/boost/tools/build/test/project-test3/readme.txt b/src/boost/tools/build/test/project-test3/readme.txt new file mode 100644 index 00000000..da27e54b --- /dev/null +++ b/src/boost/tools/build/test/project-test3/readme.txt @@ -0,0 +1,7 @@ +Copyright 2002 Vladimir Prus +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +This test checks that we have minimally working 'make' rule and that we can use target from +different project with different project roots. diff --git a/src/boost/tools/build/test/project-test4/a.cpp b/src/boost/tools/build/test/project-test4/a.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/a.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test4/a_gcc.cpp b/src/boost/tools/build/test/project-test4/a_gcc.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/a_gcc.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test4/jamfile.jam b/src/boost/tools/build/test/project-test4/jamfile.jam new file mode 100644 index 00000000..a34d5f2d --- /dev/null +++ b/src/boost/tools/build/test/project-test4/jamfile.jam @@ -0,0 +1,11 @@ +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +project test : requirements <include>everything <threading>single ; + +make a.exe : a.obj lib//b.obj/<optimization>speed : yfc-link ; +make b.exe : a.obj : yfc-link : <define>MACROS ; +make a.obj : a.cpp : yfc-compile ; diff --git a/src/boost/tools/build/test/project-test4/jamfile3.jam b/src/boost/tools/build/test/project-test4/jamfile3.jam new file mode 100644 index 00000000..9770362d --- /dev/null +++ b/src/boost/tools/build/test/project-test4/jamfile3.jam @@ -0,0 +1,5 @@ + +make a.exe : a.obj lib//b.obj/<optimization>on a_gcc.obj : yfc-link : <toolset>gcc ; +make a.exe : a.obj lib//b.obj/<optimization>on : yfc-link : <threading>multi ; +make a.obj : a.cpp : yfc-compile ; +make a_gcc.obj : a_gcc.cpp : yfc-compile ; diff --git a/src/boost/tools/build/test/project-test4/jamfile4.jam b/src/boost/tools/build/test/project-test4/jamfile4.jam new file mode 100644 index 00000000..e3257801 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/jamfile4.jam @@ -0,0 +1,4 @@ + +project test : requirements <include>everything <threading>single ; + +build-project lib2 ; diff --git a/src/boost/tools/build/test/project-test4/jamfile5.jam b/src/boost/tools/build/test/project-test4/jamfile5.jam new file mode 100644 index 00000000..1010be5e --- /dev/null +++ b/src/boost/tools/build/test/project-test4/jamfile5.jam @@ -0,0 +1,6 @@ + +project test : requirements <include>everything <threading>single ; + +make a.exe : a.obj lib//b.obj/<variant>release : yfc-link ; +make b.exe : a.obj : yfc-link : <define>MACROS ; +make a.obj : a.cpp : yfc-compile ; diff --git a/src/boost/tools/build/test/project-test4/jamroot.jam b/src/boost/tools/build/test/project-test4/jamroot.jam new file mode 100644 index 00000000..d8cf571a --- /dev/null +++ b/src/boost/tools/build/test/project-test4/jamroot.jam @@ -0,0 +1,68 @@ +# Copyright 2002, 2003, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import os ; +import gcc ; +import property ; +import toolset ; + +rule properties-as-path ( properties * ) +{ + local r ; + for local p in $(properties) + { + if $(p:G) != <action> + { + r += $(p) ; + } + } + return [ property.as-path + [ property.remove incidental : $(r) ] ] ; +} + + +toolset.flags yfc-compile KNOWN-PROPERTIES : <toolset> <optimization> ; +toolset.flags yfc-link KNOWN-PROPERTIES : <toolset> <optimization> ; + + +rule yfc-compile ( target : sources * : property-set * ) +{ + PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ; +} + +actions yfc-compile +{ + echo $(PROPERTIES) > $(<) + echo $(>) >> $(<) +} + +rule yfc-link ( target : sources * : property-set * ) +{ + PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ; +} + +actions yfc-link +{ + echo $(PROPERTIES) > $(<) + echo $(>) >> $(<) +} + +if [ os.name ] = VMS +{ + actions yfc-compile + { + PIPE WRITE SYS$OUTPUT "$(PROPERTIES)" | TYPE SYS$INPUT /OUT=$(<:W) + PIPE WRITE SYS$OUTPUT "$(>:J= ",")" | APPEND /NEW SYS$INPUT $(<:W) + } + + actions yfc-link + { + PIPE WRITE SYS$OUTPUT "$(PROPERTIES)" | TYPE SYS$INPUT /OUT=$(<:W) + OPEN /APPEND FOUT $(<:W) + WRITE FOUT "$(>:J= ",")" + CLOSE FOUT + } +} + +#IMPORT $(__name__) : yfc-compile yfc-link : : yfc-compile yfc-link ; diff --git a/src/boost/tools/build/test/project-test4/lib/b.cpp b/src/boost/tools/build/test/project-test4/lib/b.cpp new file mode 100644 index 00000000..ccecbb41 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib/b.cpp @@ -0,0 +1,8 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// diff --git a/src/boost/tools/build/test/project-test4/lib/jamfile.jam b/src/boost/tools/build/test/project-test4/lib/jamfile.jam new file mode 100644 index 00000000..1bdb7c12 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib/jamfile.jam @@ -0,0 +1,6 @@ +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +make b.obj : b.cpp : yfc-compile ; diff --git a/src/boost/tools/build/test/project-test4/lib/jamfile1.jam b/src/boost/tools/build/test/project-test4/lib/jamfile1.jam new file mode 100644 index 00000000..be2c3649 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib/jamfile1.jam @@ -0,0 +1,2 @@ + +make b.obj : b.cpp : yfc-compile ; diff --git a/src/boost/tools/build/test/project-test4/lib/jamfile2.jam b/src/boost/tools/build/test/project-test4/lib/jamfile2.jam new file mode 100644 index 00000000..d47274bd --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib/jamfile2.jam @@ -0,0 +1,4 @@ + +project lib : requirements <threading>multi ; + +make b.obj : b.cpp : yfc-compile ; diff --git a/src/boost/tools/build/test/project-test4/lib/jamfile3.jam b/src/boost/tools/build/test/project-test4/lib/jamfile3.jam new file mode 100644 index 00000000..73a78324 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib/jamfile3.jam @@ -0,0 +1,2 @@ + +make b.obj : b.cpp : yfc-compile : <rtti>off ; diff --git a/src/boost/tools/build/test/project-test4/lib2/jamfile.jam b/src/boost/tools/build/test/project-test4/lib2/jamfile.jam new file mode 100644 index 00000000..389492bf --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib2/jamfile.jam @@ -0,0 +1,8 @@ +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +project + : requirements <rtti>off + ; diff --git a/src/boost/tools/build/test/project-test4/lib2/jamfile2.jam b/src/boost/tools/build/test/project-test4/lib2/jamfile2.jam new file mode 100644 index 00000000..94b144d0 --- /dev/null +++ b/src/boost/tools/build/test/project-test4/lib2/jamfile2.jam @@ -0,0 +1,4 @@ + +project mylib + : requirements <rtti>off + ; diff --git a/src/boost/tools/build/test/project-test4/readme.txt b/src/boost/tools/build/test/project-test4/readme.txt new file mode 100644 index 00000000..0c0ba2ca --- /dev/null +++ b/src/boost/tools/build/test/project-test4/readme.txt @@ -0,0 +1,6 @@ +Copyright 2002 Vladimir Prus +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +This test checks for correct properties of generated and used targets. diff --git a/src/boost/tools/build/test/project_dependencies.py b/src/boost/tools/build/test/project_dependencies.py new file mode 100644 index 00000000..600bc0ed --- /dev/null +++ b/src/boost/tools/build/test/project_dependencies.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that we can specify a dependency property in project requirements, and +# that it will not cause every main target in the project to be generated in its +# own subdirectory. + +# The whole test is somewhat moot now. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "build-project src ;") + +t.write("lib/jamfile.jam", "lib lib1 : lib1.cpp ;") + +t.write("lib/lib1.cpp", """ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() {}\n +""") + +t.write("src/jamfile.jam", """ +project : requirements <library>../lib//lib1 ; +exe a : a.cpp ; +exe b : b.cpp ; +""") + +t.write("src/a.cpp", """ +#ifdef _WIN32 +__declspec(dllimport) +#endif +void foo(); +int main() { foo(); } +""") + +t.copy("src/a.cpp", "src/b.cpp") + +t.run_build_system() + +# Test that there is no "main-target-a" part. +# t.expect_addition("src/bin/$toolset/debug*/a.exe") +# t.expect_addition("src/bin/$toolset/debug*/b.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/project_glob.py b/src/boost/tools/build/test/project_glob.py new file mode 100644 index 00000000..362b450d --- /dev/null +++ b/src/boost/tools/build/test/project_glob.py @@ -0,0 +1,212 @@ +#!/usr/bin/python + +# Copyright (C) 2003. Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'glob' rule in Jamfile context. + +import BoostBuild + + +def test_basic(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "") + t.write("d1/a.cpp", "int main() {}\n") + t.write("d1/jamfile.jam", "exe a : [ glob *.cpp ] ../d2/d//l ;") + t.write("d2/d/l.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +void force_import_lib_creation() {} +#endif +""") + t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;") + t.write("d3/d/jamfile.jam", "exe a : [ glob ../*.cpp ] ;") + t.write("d3/a.cpp", "int main() {}\n") + + t.run_build_system(subdir="d1") + t.expect_addition("d1/bin/$toolset/debug*/a.exe") + + t.run_build_system(subdir="d3/d") + t.expect_addition("d3/d/bin/$toolset/debug*/a.exe") + + t.rm("d2/d/bin") + t.run_build_system(subdir="d2/d") + t.expect_addition("d2/d/bin/$toolset/debug*/l.dll") + + t.cleanup() + + +def test_source_location(): + """ + Test that when 'source-location' is explicitly-specified glob works + relative to the source location. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "") + t.write("d1/a.cpp", "very bad non-compilable file\n") + t.write("d1/src/a.cpp", "int main() {}\n") + t.write("d1/jamfile.jam", """\ +project : source-location src ; +exe a : [ glob *.cpp ] ../d2/d//l ; +""") + t.write("d2/d/l.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +void force_import_lib_creation() {} +#endif +""") + t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;") + + t.run_build_system(subdir="d1") + t.expect_addition("d1/bin/$toolset/debug*/a.exe") + + t.cleanup() + + +def test_wildcards_and_exclusion_patterns(): + """ + Test that wildcards can include directories. Also test exclusion + patterns. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "") + t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n") + t.write("d1/src/bar/b.cpp", "void bar() {}\n") + t.write("d1/src/bar/bad.cpp", "very bad non-compilable file\n") + t.write("d1/jamfile.jam", """\ +project : source-location src ; +exe a : [ glob foo/*.cpp bar/*.cpp : bar/bad* ] ../d2/d//l ; +""") + t.write("d2/d/l.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +void force_import_lib_creation() {} +#endif +""") + t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;") + + t.run_build_system(subdir="d1") + t.expect_addition("d1/bin/$toolset/debug*/a.exe") + + t.cleanup() + + +def test_glob_tree(): + """Test that 'glob-tree' works.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "") + t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n") + t.write("d1/src/bar/b.cpp", "void bar() {}\n") + t.write("d1/src/bar/bad.cpp", "very bad non-compilable file\n") + t.write("d1/jamfile.jam", """\ +project : source-location src ; +exe a : [ glob-tree *.cpp : bad* ] ../d2/d//l ; +""") + t.write("d2/d/l.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +void force_import_lib_creation() {} +#endif +""") + t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;") + + t.run_build_system(subdir="d1") + t.expect_addition("d1/bin/$toolset/debug*/a.exe") + + t.cleanup() + + +def test_directory_names_in_glob_tree(): + """Test that directory names in patterns for 'glob-tree' are rejected.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "") + t.write("d1/src/a.cpp", "very bad non-compilable file\n") + t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n") + t.write("d1/src/bar/b.cpp", "void bar() {}\n") + t.write("d1/src/bar/bad.cpp", "very bad non-compilable file\n") + t.write("d1/jamfile.jam", """\ +project : source-location src ; +exe a : [ glob-tree foo/*.cpp bar/*.cpp : bad* ] ../d2/d//l ; +""") + t.write("d2/d/l.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +void force_import_lib_creation() {} +#endif +""") + t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;") + + t.run_build_system(subdir="d1", status=1) + t.expect_output_lines("error: The patterns * may not include directory") + + t.cleanup() + + +def test_glob_with_absolute_names(): + """Test that 'glob' works with absolute names.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "") + t.write("d1/src/a.cpp", "very bad non-compilable file\n") + t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n") + t.write("d1/src/bar/b.cpp", "void bar() {}\n") + # Note that to get the current dir, we use bjam's PWD, not Python's + # os.getcwd(), because the former will always return a long path while the + # latter might return a short path, which would confuse path.glob. + t.write("d1/jamfile.jam", """\ +project : source-location src ; +local pwd = [ PWD ] ; # Always absolute. +exe a : [ glob $(pwd)/src/foo/*.cpp $(pwd)/src/bar/*.cpp ] ../d2/d//l ; +""") + t.write("d2/d/l.cpp", """\ +#if defined(_WIN32) +__declspec(dllexport) +void force_import_lib_creation() {} +#endif +""") + t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;") + + t.run_build_system(subdir="d1") + t.expect_addition("d1/bin/$toolset/debug*/a.exe") + + t.cleanup() + + +def test_glob_excludes_in_subdirectory(): + """ + Regression test: glob excludes used to be broken when building from a + subdirectory. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("jamroot.jam", "build-project p ;") + t.write("p/p.c", "int main() {}\n") + t.write("p/p_x.c", "very bad non-compilable file\n") + t.write("p/jamfile.jam", "exe p : [ glob *.c : p_x.c ] ;") + + t.run_build_system(subdir="p") + t.expect_addition("p/bin/$toolset/debug*/p.exe") + + t.cleanup() + + +test_basic() +test_source_location() +test_wildcards_and_exclusion_patterns() +test_glob_tree() +test_directory_names_in_glob_tree() +test_glob_with_absolute_names() +test_glob_excludes_in_subdirectory() diff --git a/src/boost/tools/build/test/project_id.py b/src/boost/tools/build/test/project_id.py new file mode 100755 index 00000000..6477f595 --- /dev/null +++ b/src/boost/tools/build/test/project_id.py @@ -0,0 +1,414 @@ +#!/usr/bin/python + +# Copyright (C) 2012. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests Boost Build's project-id handling. + +import BoostBuild +import sys + + +def test_assigning_project_ids(): + t = BoostBuild.Tester(pass_toolset=False) + t.write("jamroot.jam", """\ +import assert ; +import modules ; +import notfile ; +import project ; + +rule assert-project-id ( id ? : module-name ? ) +{ + module-name ?= [ CALLER_MODULE ] ; + assert.result $(id) : project.attribute $(module-name) id ; +} + +# Project rule modifies the main project id. +assert-project-id ; # Initial project id is empty +project foo ; assert-project-id /foo ; +project ; assert-project-id /foo ; +project foo ; assert-project-id /foo ; +project bar ; assert-project-id /bar ; +project /foo ; assert-project-id /foo ; +project "" ; assert-project-id /foo ; + +# Calling the use-project rule does not modify the project's main id. +use-project id1 : a ; +# We need to load the 'a' Jamfile module manually as the use-project rule will +# only schedule the load to be done after the current module load finishes. +a-module = [ project.load a ] ; +assert-project-id : $(a-module) ; +use-project id2 : a ; +assert-project-id : $(a-module) ; +modules.call-in $(a-module) : project baz ; +assert-project-id /baz : $(a-module) ; +use-project id3 : a ; +assert-project-id /baz : $(a-module) ; + +# Make sure the project id still holds after all the scheduled use-project loads +# complete. We do this by scheduling the assert for the Jam action scheduling +# phase. +notfile x : @assert-a-rule ; +rule assert-a-rule ( target : : properties * ) +{ + assert-project-id /baz : $(a-module) ; +} +""") + t.write("a/jamfile.jam", """\ +# Initial project id for this module is empty. +assert-project-id ; +""") + t.run_build_system() + t.cleanup() + + +def test_using_project_ids_in_target_references(): + t = BoostBuild.Tester() + __write_appender(t, "appender.jam") + t.write("jamroot.jam", """\ +import type ; +type.register AAA : _a ; +type.register BBB : _b ; + +import appender ; +appender.register aaa-to-bbb : AAA : BBB ; + +use-project id1 : a ; +use-project /id2 : a ; + +bbb b1 : /id1//target ; +bbb b2 : /id2//target ; +bbb b3 : /id3//target ; +bbb b4 : a//target ; +bbb b5 : /project-a1//target ; +bbb b6 : /project-a2//target ; +bbb b7 : /project-a3//target ; + +use-project id3 : a ; +""") + t.write("a/source._a", "") + t.write("a/jamfile.jam", """\ +project project-a1 ; +project /project-a2 ; +import alias ; +alias target : source._a ; +project /project-a3 ; +""") + + t.run_build_system() + t.expect_addition("bin/b%d._b" % x for x in range(1, 8)) + t.expect_nothing_more() + + t.cleanup() + + +def test_repeated_ids_for_different_projects(): + t = BoostBuild.Tester() + + t.write("a/jamfile.jam", "") + t.write("jamroot.jam", "project foo ; use-project foo : a ;") + t.run_build_system(status=1) + t.expect_output_lines("""\ +error: Attempt to redeclare already registered project id '/foo'. +error: Original project: +error: Name: Jamfile<*> +error: Module: Jamfile<*> +error: Main id: /foo +error: File: jamroot.jam +error: Location: . +error: New project: +error: Module: Jamfile<*> +error: File: a*jamfile.jam +error: Location: a""") + + t.write("jamroot.jam", "use-project foo : a ; project foo ;") + t.run_build_system(status=1) + t.expect_output_lines("""\ +error: Attempt to redeclare already registered project id '/foo'. +error: Original project: +error: Name: Jamfile<*> +error: Module: Jamfile<*> +error: Main id: /foo +error: File: jamroot.jam +error: Location: . +error: New project: +error: Module: Jamfile<*> +error: File: a*jamfile.jam +error: Location: a""") + + t.write("jamroot.jam", """\ +import modules ; +import project ; +modules.call-in [ project.load a ] : project foo ; +project foo ; +""") + t.run_build_system(status=1) + t.expect_output_lines("""\ +error: at jamroot.jam:4 +error: Attempt to redeclare already registered project id '/foo'. +error: Original project: +error: Name: Jamfile<*> +error: Module: Jamfile<*> +error: Main id: /foo +error: File: a*jamfile.jam +error: Location: a +error: New project: +error: Module: Jamfile<*> +error: File: jamroot.jam +error: Location: .""") + + t.cleanup() + + +def test_repeated_ids_for_same_project(): + t = BoostBuild.Tester() + + t.write("jamroot.jam", "project foo ; project foo ;") + t.run_build_system() + + t.write("jamroot.jam", "project foo ; use-project foo : . ;") + t.run_build_system() + + t.write("jamroot.jam", "project foo ; use-project foo : ./. ;") + t.run_build_system() + + t.write("jamroot.jam", """\ +project foo ; +use-project foo : . ; +use-project foo : ./aaa/.. ; +use-project foo : ./. ; +""") + t.run_build_system() + + # On Windows we have a case-insensitive file system and we can use + # backslashes as path separators. + # FIXME: Make a similar test pass on Cygwin. + if sys.platform in ['win32']: + t.write("a/fOo bAr/b/jamfile.jam", "") + t.write("jamroot.jam", r""" +use-project bar : "a/foo bar/b" ; +use-project bar : "a/foO Bar/b" ; +use-project bar : "a/foo BAR/b/" ; +use-project bar : "a\\.\\FOO bar\\b\\" ; +""") + t.run_build_system() + t.rm("a") + + t.write("bar/jamfile.jam", "") + t.write("jamroot.jam", """\ +use-project bar : bar ; +use-project bar : bar/ ; +use-project bar : bar// ; +use-project bar : bar/// ; +use-project bar : bar//// ; +use-project bar : bar/. ; +use-project bar : bar/./ ; +use-project bar : bar/////./ ; +use-project bar : bar/../bar/xxx/.. ; +use-project bar : bar/..///bar/xxx///////.. ; +use-project bar : bar/./../bar/xxx/.. ; +use-project bar : bar/.////../bar/xxx/.. ; +use-project bar : bar/././../bar/xxx/.. ; +use-project bar : bar/././//////////../bar/xxx/.. ; +use-project bar : bar/.///.////../bar/xxx/.. ; +use-project bar : bar/./././xxx/.. ; +use-project bar : bar/xxx////.. ; +use-project bar : bar/xxx/.. ; +use-project bar : bar///////xxx/.. ; +""") + t.run_build_system() + t.rm("bar") + + # On Windows we have a case-insensitive file system and we can use + # backslashes as path separators. + # FIXME: Make a similar test pass on Cygwin. + if sys.platform in ['win32']: + t.write("baR/jamfile.jam", "") + t.write("jamroot.jam", r""" +use-project bar : bar ; +use-project bar : BAR ; +use-project bar : bAr ; +use-project bar : bAr/ ; +use-project bar : bAr\\ ; +use-project bar : bAr\\\\ ; +use-project bar : bAr\\\\///// ; +use-project bar : bAr/. ; +use-project bar : bAr/./././ ; +use-project bar : bAr\\.\\.\\.\\ ; +use-project bar : bAr\\./\\/.\\.\\ ; +use-project bar : bAr/.\\././ ; +use-project bar : Bar ; +use-project bar : BaR ; +use-project bar : BaR/./../bAr/xxx/.. ; +use-project bar : BaR/./..\\bAr\\xxx/.. ; +use-project bar : BaR/xxx/.. ; +use-project bar : BaR///\\\\\\//xxx/.. ; +use-project bar : Bar\\xxx/.. ; +use-project bar : BAR/xXx/.. ; +use-project bar : BAR/xXx\\\\/\\/\\//\\.. ; +""") + t.run_build_system() + t.rm("baR") + + t.cleanup() + + +def test_unresolved_project_references(): + t = BoostBuild.Tester() + + __write_appender(t, "appender.jam") + t.write("a/source._a", "") + t.write("a/jamfile.jam", "import alias ; alias target : source._a ;") + t.write("jamroot.jam", """\ +import type ; +type.register AAA : _a ; +type.register BBB : _b ; + +import appender ; +appender.register aaa-to-bbb : AAA : BBB ; + +use-project foo : a ; + +bbb b1 : a//target ; +bbb b2 : /foo//target ; +bbb b-invalid : invalid//target ; +bbb b-root-invalid : /invalid//target ; +bbb b-missing-root : foo//target ; +bbb b-invalid-target : /foo//invalid ; +""") + + t.run_build_system(["b1", "b2"]) + t.expect_addition("bin/b%d._b" % x for x in range(1, 3)) + t.expect_nothing_more() + + t.run_build_system(["b-invalid"], status=1) + t.expect_output_lines("""\ +error: Unable to find file or target named +error: 'invalid//target' +error: referred to from project at +error: '.' +error: could not resolve project reference 'invalid'""") + + t.run_build_system(["b-root-invalid"], status=1) + t.expect_output_lines("""\ +error: Unable to find file or target named +error: '/invalid//target' +error: referred to from project at +error: '.' +error: could not resolve project reference '/invalid'""") + + t.run_build_system(["b-missing-root"], status=1) + t.expect_output_lines("""\ +error: Unable to find file or target named +error: 'foo//target' +error: referred to from project at +error: '.' +error: could not resolve project reference 'foo' - possibly missing a """ + "leading slash ('/') character.") + + t.run_build_system(["b-invalid-target"], status=1) + t.expect_output_lines("""\ +error: Unable to find file or target named +error: '/foo//invalid' +error: referred to from project at +error: '.'""") + t.expect_output_lines("*could not resolve project reference*", False) + + t.cleanup() + + +def __write_appender(t, name): + t.write(name, +r"""# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Support for registering test generators that construct their targets by +# simply appending their given input data, e.g. list of sources & targets. + +import "class" : new ; +import generators ; +import modules ; +import sequence ; + +rule register ( id composing ? : source-types + : target-types + ) +{ + local caller-module = [ CALLER_MODULE ] ; + id = $(caller-module).$(id) ; + local g = [ new generator $(id) $(composing) : $(source-types) : + $(target-types) ] ; + $(g).set-rule-name $(__name__).appender ; + generators.register $(g) ; + return $(id) ; +} + +if [ modules.peek : NT ] +{ + X = ")" ; + ECHO_CMD = (echo. ; +} +else +{ + X = \" ; + ECHO_CMD = "echo $(X)" ; +} + +local appender-runs ; + +# We set up separate actions for building each target in order to avoid having +# to iterate over them in action (i.e. shell) code. We have to be extra careful +# though to achieve the exact same effect as if doing all the work in just one +# action. Otherwise Boost Jam might, under some circumstances, run only some of +# our actions. To achieve this we register a series of actions for all the +# targets (since they all have the same target list - either all or none of them +# get run independent of which target actually needs to get built), each +# building only a single target. Since all our actions use the same targets, we +# can not use 'on-target' parameters to pass data to a specific action so we +# pass them using the second 'sources' parameter which our actions then know how +# to interpret correctly. This works well since Boost Jam does not automatically +# add dependency relations between specified action targets & sources and so the +# second argument, even though most often used to pass in a list of sources, can +# actually be used for passing in any type of information. +rule appender ( targets + : sources + : properties * ) +{ + appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ; + local target-index = 0 ; + local target-count = [ sequence.length $(targets) ] ; + local original-targets ; + for t in $(targets) + { + target-index = [ CALC $(target-index) + 1 ] ; + local appender-run = $(appender-runs) ; + if $(targets[2])-defined + { + appender-run += [$(target-index)/$(target-count)] ; + } + append $(targets) : $(appender-run:J=" ") $(t) $(sources) ; + } +} + +actions append +{ + $(ECHO_CMD)-------------------------------------------------$(X) + $(ECHO_CMD)Appender run: $(>[1])$(X) + $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])" + $(ECHO_CMD)Target group: $(<:J=' ')$(X) + $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])" + $(ECHO_CMD) Target: '$(>[2])'$(X) + $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])" + $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X) + $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])" + $(ECHO_CMD)=================================================$(X) + $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])" +} +""") + + +test_assigning_project_ids() +test_using_project_ids_in_target_references() +test_repeated_ids_for_same_project() +test_repeated_ids_for_different_projects() +test_unresolved_project_references() diff --git a/src/boost/tools/build/test/project_root_constants.py b/src/boost/tools/build/test/project_root_constants.py new file mode 100644 index 00000000..b3bdcbb2 --- /dev/null +++ b/src/boost/tools/build/test/project_root_constants.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +# Copyright 2003, 2004, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +# Create a temporary working directory. +t = BoostBuild.Tester() + +# Create the needed files. +t.write("jamroot.jam", """\ +constant FOO : foobar gee ; +ECHO $(FOO) ; +""") + +t.run_build_system() +t.expect_output_lines("foobar gee") + +# Regression test: when absolute paths were passed to path-constant rule, +# Boost.Build failed to recognize path as absolute and prepended the current +# dir. +t.write("jamroot.jam", """\ +import path ; +local here = [ path.native [ path.pwd ] ] ; +path-constant HERE : $(here) ; +if $(HERE) != $(here) +{ + ECHO "PWD =" $(here) ; + ECHO "path constant =" $(HERE) ; + EXIT ; +} +""") +t.write("jamfile.jam", "") + +t.run_build_system() + +t.write("jamfile.jam", """\ +# This tests that rule 'hello' will be imported to children unlocalized, and +# will still access variables in this Jamfile. +x = 10 ; +constant FOO : foo ; +rule hello ( ) { ECHO "Hello $(x)" ; } +""") + +t.write("d/jamfile.jam", """\ +ECHO "d: $(FOO)" ; +constant BAR : bar ; +""") + +t.write("d/d2/jamfile.jam", """\ +ECHO "d2: $(FOO)" ; +ECHO "d2: $(BAR)" ; +hello ; +""") + +t.run_build_system(subdir="d/d2") +t.expect_output_lines("d: foo\nd2: foo\nd2: bar\nHello 10") + +t.cleanup() diff --git a/src/boost/tools/build/test/project_root_rule.py b/src/boost/tools/build/test/project_root_rule.py new file mode 100644 index 00000000..503b3cad --- /dev/null +++ b/src/boost/tools/build/test/project_root_rule.py @@ -0,0 +1,34 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2005. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests that we can declare a rule in Jamroot that will be can be called in +# child Jamfile to declare a target. Specifically test for use of 'glob' in that +# rule. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + + +t.write("jamroot.jam", """ +project : requirements <link>static ; +rule my-lib ( name ) { lib $(name) : [ glob *.cpp ] ; } +""") + +t.write("sub/a.cpp", """ +""") + +t.write("sub/jamfile.jam", """ +my-lib foo ; +""") + + +t.run_build_system(subdir="sub") + +t.expect_addition("sub/bin/$toolset/debug*/foo.lib") + +t.cleanup() diff --git a/src/boost/tools/build/test/project_test3.py b/src/boost/tools/build/test/project_test3.py new file mode 100644 index 00000000..9203cd88 --- /dev/null +++ b/src/boost/tools/build/test/project_test3.py @@ -0,0 +1,135 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Dave Abrahams +# Copyright 2002, 2003, 2004, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +t = BoostBuild.Tester(translate_suffixes=0) + +# First check some startup. +t.set_tree("project-test3") +os.remove("jamroot.jam") +t.run_build_system(status=1) + +t.expect_output_lines("*.yfc-compile\" unknown in module*") + +t.set_tree("project-test3") +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/a.obj") +t.expect_content("bin/$toolset/debug*/a.obj", """\ +$toolset/debug* +a.cpp +""") + +t.expect_addition("bin/$toolset/debug*/a.exe") +t.expect_content("bin/$toolset/debug*/a.exe", +"$toolset/debug*\n" + +"bin/$toolset/debug*/a.obj lib/bin/$toolset/debug*/b.obj " + +"lib2/bin/$toolset/debug*/c.obj lib2/bin/$toolset/debug*/d.obj " + +"lib2/helper/bin/$toolset/debug*/e.obj " + +"lib3/bin/$toolset/debug*/f.obj\n" +) + +t.expect_addition("lib/bin/$toolset/debug*/b.obj") +t.expect_content("lib/bin/$toolset/debug*/b.obj", """\ +$toolset/debug* +lib/b.cpp +""") + +t.expect_addition("lib/bin/$toolset/debug*/m.exe") +t.expect_content("lib/bin/$toolset/debug*/m.exe", """\ +$toolset/debug* +lib/bin/$toolset/debug*/b.obj lib2/bin/$toolset/debug*/c.obj +""") + +t.expect_addition("lib2/bin/$toolset/debug*/c.obj") +t.expect_content("lib2/bin/$toolset/debug*/c.obj", """\ +$toolset/debug* +lib2/c.cpp +""") + +t.expect_addition("lib2/bin/$toolset/debug*/d.obj") +t.expect_content("lib2/bin/$toolset/debug*/d.obj", """\ +$toolset/debug* +lib2/d.cpp +""") + +t.expect_addition("lib2/bin/$toolset/debug*/l.exe") +t.expect_content("lib2/bin/$toolset/debug*/l.exe", """\ +$toolset/debug* +lib2/bin/$toolset/debug*/c.obj bin/$toolset/debug*/a.obj +""") + +t.expect_addition("lib2/helper/bin/$toolset/debug*/e.obj") +t.expect_content("lib2/helper/bin/$toolset/debug*/e.obj", """\ +$toolset/debug* +lib2/helper/e.cpp +""") + +t.expect_addition("lib3/bin/$toolset/debug*/f.obj") +t.expect_content("lib3/bin/$toolset/debug*/f.obj", """\ +$toolset/debug* +lib3/f.cpp lib2/helper/bin/$toolset/debug*/e.obj +""") + +t.touch("a.cpp") +t.run_build_system() +t.expect_touch(["bin/$toolset/debug*/a.obj", + "bin/$toolset/debug*/a.exe", + "lib2/bin/$toolset/debug*/l.exe"]) + +t.run_build_system(["release", "optimization=off,speed"]) +t.expect_addition(["bin/$toolset/release/optimization-off*/a.exe", + "bin/$toolset/release/optimization-off*/a.obj", + "bin/$toolset/release*/a.exe", + "bin/$toolset/release*/a.obj"]) + +t.run_build_system(["--clean-all"]) +t.expect_removal(["bin/$toolset/debug*/a.obj", + "bin/$toolset/debug*/a.exe", + "lib/bin/$toolset/debug*/b.obj", + "lib/bin/$toolset/debug*/m.exe", + "lib2/bin/$toolset/debug*/c.obj", + "lib2/bin/$toolset/debug*/d.obj", + "lib2/bin/$toolset/debug*/l.exe", + "lib3/bin/$toolset/debug*/f.obj"]) + +# Now test target ids in command line. +t.set_tree("project-test3") +t.run_build_system(["lib//b.obj"]) +t.expect_addition("lib/bin/$toolset/debug*/b.obj") +t.expect_nothing_more() + +t.run_build_system(["--clean", "lib//b.obj"]) +t.expect_removal("lib/bin/$toolset/debug*/b.obj") +t.expect_nothing_more() + +t.run_build_system(["lib//b.obj"]) +t.expect_addition("lib/bin/$toolset/debug*/b.obj") +t.expect_nothing_more() + +t.run_build_system(["release", "lib2/helper//e.obj", "/lib3//f.obj"]) +t.expect_addition("lib2/helper/bin/$toolset/release*/e.obj") +t.expect_addition("lib3/bin/$toolset/release*/f.obj") +t.expect_nothing_more() + +# Test project ids in command line work as well. +t.set_tree("project-test3") +t.run_build_system(["/lib2"]) +t.expect_addition("lib2/bin/$toolset/debug*/" * + BoostBuild.List("c.obj d.obj l.exe")) +t.expect_addition("bin/$toolset/debug*/a.obj") +t.expect_nothing_more() + +t.run_build_system(["lib"]) +t.expect_addition("lib/bin/$toolset/debug*/" * + BoostBuild.List("b.obj m.exe")) +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/project_test4.py b/src/boost/tools/build/test/project_test4.py new file mode 100644 index 00000000..45faf0dc --- /dev/null +++ b/src/boost/tools/build/test/project_test4.py @@ -0,0 +1,65 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(translate_suffixes=0) + + +t.set_tree("project-test4") + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/a.obj") +t.expect_content("bin/$toolset/debug*/a.obj", +"""$toolset/debug*/include-everything* +a.cpp +""") + +t.expect_addition("bin/$toolset/debug*/a.exe") +t.expect_content("bin/$toolset/debug*/a.exe", +"$toolset/debug*/include-everything*\n" + +"bin/$toolset/debug*/a.obj lib/bin/$toolset/debug/optimization-speed*/b.obj\n" +) + +t.expect_addition("lib/bin/$toolset/debug/optimization-speed*/b.obj") +t.expect_content("lib/bin/$toolset/debug/optimization-speed*/b.obj", +"""$toolset/debug/include-everything/optimization-speed* +lib/b.cpp +""") + +t.expect_addition("bin/$toolset/debug*/b.exe") +t.expect_content("bin/$toolset/debug*/b.exe", +"$toolset/debug/define-MACROS/include-everything*\n" + +"bin/$toolset/debug*/a.obj\n" +) + +t.copy("lib/jamfile3.jam", "lib/jamfile.jam") + +# Link-compatibility check for rtti is disabled... +#t.run_build_system(status=None) +#import string +#t.fail_test(t.stdout().find( +#"""warning: targets produced from b.obj are link incompatible +#warning: with main target a.exe""") !=-0) + +# Test that if we specified composite property in target reference, everything +# works OK. + +t.copy("lib/jamfile1.jam", "lib/jamfile.jam") +t.copy("jamfile5.jam", "jamfile.jam") + +t.run_build_system() + +t.expect_addition("lib/bin/$toolset/release*/b.obj") + +t.expect_content("bin/$toolset/debug*/a.exe", +"$toolset/debug/include-everything*\n" + +"bin/$toolset/debug*/a.obj lib/bin/$toolset/release*/b.obj\n" +) + +t.cleanup() diff --git a/src/boost/tools/build/test/property_expansion.py b/src/boost/tools/build/test/property_expansion.py new file mode 100644 index 00000000..53fc1361 --- /dev/null +++ b/src/boost/tools/build/test/property_expansion.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that free property inside. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """\ +variant debug-AA : debug : <define>AA ; +alias all : hello ; +exe hello : hello.cpp ; +explicit hello ; +""") + +t.write("hello.cpp", """\ +#ifdef AA +int main() {} +#endif +""") + +t.run_build_system(["debug-AA"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/qt4.py b/src/boost/tools/build/test/qt4.py new file mode 100755 index 00000000..170f6079 --- /dev/null +++ b/src/boost/tools/build/test/qt4.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +# (c) Copyright Juergen Hunold 2008 +# Use, modification, and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +# Run test in real directory in order to find Boost.Test via Boost Top-Level +# Jamroot. +qt4_dir = os.getcwd() + "/qt4" + +t = BoostBuild.Tester(workdir=qt4_dir) + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/qt4/jamroot.jam b/src/boost/tools/build/test/qt4/jamroot.jam new file mode 100644 index 00000000..3d8e7d73 --- /dev/null +++ b/src/boost/tools/build/test/qt4/jamroot.jam @@ -0,0 +1,82 @@ +# (c) Copyright Juergen Hunold 2008 +# Use, modification, and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import qt4 ; +import testing ; +import cast ; + + + +if [ qt4.initialized ] +{ + use-project /boost : ../../../.. ; + + project qttest + : requirements + <library>/boost/test//boost_unit_test_framework + ; + + alias qt-tests : + # Check for explicit libraries, <use>/qt should not link any lib + [ link-fail qtcorefail.cpp : <use>/qt ] + + [ run qtcore.cpp /qt//QtCore ] + [ run qtsql.cpp /qt//QtSql ] + [ run qtxml.cpp /qt//QtXml ] + [ run qtnetwork.cpp /qt//QtNetwork ] + [ run qtscript.cpp /qt//QtScript ] + [ run qtscripttools.cpp /qt//QtScriptTools ] + [ run qtxmlpatterns.cpp /qt//QtXmlPatterns ] + + # ToDo: runable example code + [ link qtsvg.cpp /qt//QtSvg ] + [ link qtgui.cpp /qt//QtGui ] + + # Multimedia toolkits. + [ link qtwebkit.cpp /qt//QtWebKit ] + [ link phonon.cpp /qt//phonon ] + [ link qtmultimedia.cpp /qt//QtMultimedia ] + + # QML + [ link qtdeclarative.cpp /qt//QtDeclarative ] + + # Help systems. + [ link qthelp.cpp /qt//QtHelp ] + [ link qtassistant.cpp /qt//QtAssistantClient : <conditional>@check_for_assistant ] + + # Check working and disabled Qt3Support + [ link qt3support.cpp /qt//Qt3Support : <qt3support>on ] + [ compile-fail qt3support.cpp /qt//Qt3Support : <qt3support>off ] + + # Testing using QtTest. Simple sample + # ToDo: better support for "automoc" aka '#include "qttest.moc"' + [ run qttest.cpp [ cast _ moccable-cpp : qttest.cpp ] /qt//QtTest : : : <define>TEST_MOCK ] + + # Test moc rule + [ run mock.cpp mock.h /qt//QtCore : : : <define>TEST_MOCK ] + + # Test resource compiler + [ run rcc.cpp rcc.qrc /qt//QtCore : : : <rccflags>"-compress 9 -threshold 10" ] + + : # requirements + : # default-build + : # usage-requirements + ; +} + +# QtAssistant is removed from Qt >= 4.6 +rule check_for_assistant ( properties * ) +{ + # Extract version number from toolset + local version = [ MATCH "<qt>([0-9.]+).*" + : $(properties) ] ; + + if $(version) > "4.6.99" + { + result += <build>no ; + } +} + + diff --git a/src/boost/tools/build/test/qt4/mock.cpp b/src/boost/tools/build/test/qt4/mock.cpp new file mode 100644 index 00000000..8f7a35c2 --- /dev/null +++ b/src/boost/tools/build/test/qt4/mock.cpp @@ -0,0 +1,26 @@ +// (c) Copyright Juergen Hunold 2011 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtMoc + +#include "mock.h" + +#include <boost/test/unit_test.hpp> + +Mock::Mock() +{ +} + +/*! + Check that the compiler get the correct #defines. + The logic to test the moc is in the header file "mock.h" + */ +BOOST_AUTO_TEST_CASE(construct_mock) +{ + delete new Mock(); + + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(TEST_MOCK), true); +} diff --git a/src/boost/tools/build/test/qt4/mock.h b/src/boost/tools/build/test/qt4/mock.h new file mode 100644 index 00000000..1cc95b05 --- /dev/null +++ b/src/boost/tools/build/test/qt4/mock.h @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2011 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <QtCore/QObject> + +class Mock : public QObject +{ + /*! + Test that the moc gets the necessary #defines + Else the moc will not see the Q_OBJECT macro, issue a warning + and linking will fail due to missing vtable symbols. + */ +#if defined(TEST_MOCK) + Q_OBJECT +#endif + public: + + Mock(); +}; diff --git a/src/boost/tools/build/test/qt4/phonon.cpp b/src/boost/tools/build/test/qt4/phonon.cpp new file mode 100644 index 00000000..3151f591 --- /dev/null +++ b/src/boost/tools/build/test/qt4/phonon.cpp @@ -0,0 +1,23 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtPhonon + +#include <phonon/MediaObject> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_PHONON_LIB), true); +} + +BOOST_AUTO_TEST_CASE( phonon_object) +{ + Phonon::MediaObject player; +} diff --git a/src/boost/tools/build/test/qt4/qt3support.cpp b/src/boost/tools/build/test/qt4/qt3support.cpp new file mode 100644 index 00000000..35d8c73b --- /dev/null +++ b/src/boost/tools/build/test/qt4/qt3support.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE Qt3Support + +#include <Q3Table> + +#include <boost/test/unit_test.hpp> + + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SQL_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_NETWORK_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_QT3SUPPORT_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT3_SUPPORT), true); +} + +BOOST_AUTO_TEST_CASE( q3table ) +{ + Q3Table q3table; + +} + diff --git a/src/boost/tools/build/test/qt4/qtassistant.cpp b/src/boost/tools/build/test/qt4/qtassistant.cpp new file mode 100644 index 00000000..e2a6ed7b --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtassistant.cpp @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtAssistant + +#include <QAssistantClient> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); +} + +BOOST_AUTO_TEST_CASE( empty_assistant) +{ + QAssistantClient client(QString()); +} diff --git a/src/boost/tools/build/test/qt4/qtcore.cpp b/src/boost/tools/build/test/qt4/qtcore.cpp new file mode 100644 index 00000000..f3c09039 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtcore.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCore +#include <QtCore> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( qstring_test) +{ + QString dummy; + + BOOST_CHECK_EQUAL(dummy.isEmpty(), true); +} diff --git a/src/boost/tools/build/test/qt4/qtcorefail.cpp b/src/boost/tools/build/test/qt4/qtcorefail.cpp new file mode 100644 index 00000000..15fd36ae --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtcorefail.cpp @@ -0,0 +1,23 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCoreFail + +#include <QtCore> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( qstring_test) +{ + QString dummy; + + BOOST_CHECK_EQUAL(dummy.isEmpty(), true); +} diff --git a/src/boost/tools/build/test/qt4/qtdeclarative.cpp b/src/boost/tools/build/test/qt4/qtdeclarative.cpp new file mode 100644 index 00000000..817855ba --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtdeclarative.cpp @@ -0,0 +1,27 @@ +// (c) Copyright Juergen Hunold 2011 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtMultimedia + +#include <QApplication> +#include <QDeclarativeView> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_DECLARATIVE_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( declarative ) +{ + QApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + QDeclarativeView view; +} diff --git a/src/boost/tools/build/test/qt4/qtgui.cpp b/src/boost/tools/build/test/qt4/qtgui.cpp new file mode 100644 index 00000000..75d9dacb --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtgui.cpp @@ -0,0 +1,42 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtGui + +#include <QApplication> + +#include <boost/test/unit_test.hpp> + +struct Fixture +{ + Fixture() + : application(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv, + false) + { + BOOST_TEST_MESSAGE( "setup QApplication fixture" ); + } + + ~Fixture() + { + BOOST_TEST_MESSAGE( "teardown QApplication fixture" ); + } + + QApplication application; +}; + +BOOST_GLOBAL_FIXTURE( Fixture ); + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( qtgui_test) +{ + BOOST_CHECK_EQUAL(true, true); +} diff --git a/src/boost/tools/build/test/qt4/qthelp.cpp b/src/boost/tools/build/test/qt4/qthelp.cpp new file mode 100644 index 00000000..32327de5 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qthelp.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtHelp + +#include <QtHelp> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); +} + +BOOST_AUTO_TEST_CASE( empty_engine) +{ + QHelpEngine engine(QString()); +} diff --git a/src/boost/tools/build/test/qt4/qtmultimedia.cpp b/src/boost/tools/build/test/qt4/qtmultimedia.cpp new file mode 100644 index 00000000..dc5914af --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtmultimedia.cpp @@ -0,0 +1,25 @@ +// (c) Copyright Juergen Hunold 2009 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtMultimedia + +#include <QAudioDeviceInfo> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_MULTIMEDIA_LIB), true); +} + +BOOST_AUTO_TEST_CASE( audiodevices) +{ + QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + for(int i = 0; i < devices.size(); ++i) { + BOOST_TEST_MESSAGE(QAudioDeviceInfo(devices.at(i)).deviceName().constData()); + } +} diff --git a/src/boost/tools/build/test/qt4/qtnetwork.cpp b/src/boost/tools/build/test/qt4/qtnetwork.cpp new file mode 100644 index 00000000..3f628d88 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtnetwork.cpp @@ -0,0 +1,33 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtNetwork + +#include <QHostInfo> + +#include <QTextStream> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_NETWORK_LIB), true); +} + +BOOST_AUTO_TEST_CASE( hostname ) +{ + QHostInfo info(QHostInfo::fromName("www.boost.org")); //blocking lookup + + QTextStream stream(stdout, QIODevice::WriteOnly); + + Q_FOREACH(QHostAddress address, info.addresses()) + { + BOOST_CHECK_EQUAL(address.isNull(), false); + stream << address.toString() << endl; + } +} diff --git a/src/boost/tools/build/test/qt4/qtscript.cpp b/src/boost/tools/build/test/qt4/qtscript.cpp new file mode 100644 index 00000000..65353dae --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtscript.cpp @@ -0,0 +1,37 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtScript + +#include <QScriptEngine> + +#include <QCoreApplication> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SCRIPT_LIB), true); +} + +BOOST_AUTO_TEST_CASE( script ) +{ + QCoreApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + QScriptEngine myEngine; + QScriptValue three = myEngine.evaluate("1 + 2"); + + BOOST_CHECK_EQUAL(three.toNumber(), 3); + BOOST_CHECK_EQUAL(three.toString(), QLatin1String("3")); +} diff --git a/src/boost/tools/build/test/qt4/qtscripttools.cpp b/src/boost/tools/build/test/qt4/qtscripttools.cpp new file mode 100644 index 00000000..4d0b7f25 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtscripttools.cpp @@ -0,0 +1,47 @@ +// (c) Copyright Juergen Hunold 2009 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtScriptTools + +#include <QScriptEngine> + +#include <QScriptEngineDebugger> + +#include <QApplication> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +namespace utf = boost::unit_test::framework; + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SCRIPTTOOLS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( script ) +{ + QApplication app(utf::master_test_suite().argc, + utf::master_test_suite().argv); + + QScriptEngine myEngine; + QScriptValue three = myEngine.evaluate("1 + 2"); + + QScriptEngineDebugger debugger; + debugger.attachTo(&myEngine); + + BOOST_CHECK_EQUAL(three.toNumber(), 3); + BOOST_CHECK_EQUAL(three.toString(), QLatin1String("3")); + + debugger.detach(); +} diff --git a/src/boost/tools/build/test/qt4/qtsql.cpp b/src/boost/tools/build/test/qt4/qtsql.cpp new file mode 100644 index 00000000..aa506b1c --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtsql.cpp @@ -0,0 +1,37 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtSql + +#include <QSqlDatabase> + +#include <QTextStream> +#include <QStringList> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SQL_LIB), true); +} + +BOOST_AUTO_TEST_CASE( drivers ) +{ + QTextStream stream(stdout, QIODevice::WriteOnly); + + Q_FOREACH(QString it, QSqlDatabase:: drivers()) + { + stream << it << endl; + } +} + +BOOST_AUTO_TEST_CASE( construct ) +{ + QSqlDatabase database; + BOOST_CHECK_EQUAL(database.isOpen(), false); +} diff --git a/src/boost/tools/build/test/qt4/qtsvg.cpp b/src/boost/tools/build/test/qt4/qtsvg.cpp new file mode 100644 index 00000000..8a139438 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtsvg.cpp @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtSvg + +#include <QtSvg> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SVG_LIB), true); +} + +BOOST_AUTO_TEST_CASE( generator_construct) +{ + QSvgGenerator generator; +} diff --git a/src/boost/tools/build/test/qt4/qttest.cpp b/src/boost/tools/build/test/qt4/qttest.cpp new file mode 100644 index 00000000..a2744cdc --- /dev/null +++ b/src/boost/tools/build/test/qt4/qttest.cpp @@ -0,0 +1,30 @@ +// (c) Copyright Juergen Hunold 2008-2011 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <QtTest> + +class QtTest: public QObject +{ + /*! + Test if the moc gets the #define + */ +#if defined(TEST_MOCK) + Q_OBJECT +#endif + +private Q_SLOTS: + void toUpper(); +}; + +void +QtTest::toUpper() +{ + QString str = "Hello"; + QCOMPARE(str.toUpper(), QString("HELLO")); +} + +QTEST_MAIN(QtTest) +#include "qttest.moc" + diff --git a/src/boost/tools/build/test/qt4/qtwebkit.cpp b/src/boost/tools/build/test/qt4/qtwebkit.cpp new file mode 100644 index 00000000..7d85f147 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtwebkit.cpp @@ -0,0 +1,24 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebKit + +#include <QWebPage> +#include <QApplication> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBKIT_LIB), true); +} + +BOOST_AUTO_TEST_CASE( webkit ) +{ + QWebPage page; + BOOST_CHECK_EQUAL(page.isModified(), false); +} diff --git a/src/boost/tools/build/test/qt4/qtxml.cpp b/src/boost/tools/build/test/qt4/qtxml.cpp new file mode 100644 index 00000000..8002c265 --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtxml.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtXml + +#include <QtXml> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); +} + +BOOST_AUTO_TEST_CASE( reader_construct) +{ + QXmlStreamReader reader; + BOOST_CHECK_EQUAL(reader.atEnd(), false); +} + +BOOST_AUTO_TEST_CASE( writer_construct) +{ + QXmlStreamWriter writer; + BOOST_CHECK_EQUAL(writer.device(), static_cast<QIODevice*>(0)); +} + diff --git a/src/boost/tools/build/test/qt4/qtxmlpatterns.cpp b/src/boost/tools/build/test/qt4/qtxmlpatterns.cpp new file mode 100644 index 00000000..6835fdad --- /dev/null +++ b/src/boost/tools/build/test/qt4/qtxmlpatterns.cpp @@ -0,0 +1,76 @@ +// (c) Copyright Juergen Hunold 2008 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtXmlPatterns + +#include <QXmlQuery> +#include <QXmlSerializer> + +#include <QCoreApplication> +#include <QString> +#include <QTextStream> +#include <QBuffer> + +#include <boost/test/unit_test.hpp> + + +struct Fixture +{ + Fixture() + : application(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv) + { + BOOST_TEST_MESSAGE( "setup QCoreApplication fixture" ); + } + + ~Fixture() + { + BOOST_TEST_MESSAGE( "teardown QCoreApplication fixture" ); + } + + QCoreApplication application; +}; + +BOOST_GLOBAL_FIXTURE( Fixture ); + +QByteArray doc("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<html xmlns=\"http://www.w3.org/1999/xhtml/\" xml:lang=\"en\" lang=\"en\">" +" <head>" +" <title>Global variables report for globals.gccxml</title>" +" </head>" +"<body><p>Some Test text</p></body></html>"); + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XMLPATTERNS_LIB), true); + + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), false); +} + +BOOST_AUTO_TEST_CASE( extract ) +{ + + QBuffer buffer(&doc); // This is a QIODevice. + buffer.open(QIODevice::ReadOnly); + QXmlQuery query; + query.bindVariable("myDocument", &buffer); + query.setQuery("declare variable $myDocument external;" + "doc($myDocument)");///p[1]"); + + BOOST_CHECK_EQUAL(query.isValid(), true); + + QByteArray result; + QBuffer out(&result); + out.open(QIODevice::WriteOnly); + + QXmlSerializer serializer(query, &out); + BOOST_CHECK_EQUAL(query.evaluateTo(&serializer), true); + + QTextStream stream(stdout); + BOOST_CHECK_EQUAL(result.isEmpty(), false); + stream << "hallo" << result << endl; +} + diff --git a/src/boost/tools/build/test/qt4/rcc.cpp b/src/boost/tools/build/test/qt4/rcc.cpp new file mode 100644 index 00000000..cae553bb --- /dev/null +++ b/src/boost/tools/build/test/qt4/rcc.cpp @@ -0,0 +1,20 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCore +#include <QtCore> + +#include <boost/test/unit_test.hpp> + +std::ostream& operator<<(std::ostream& out, QString const& text) +{ + out << text.toUtf8().constData(); + return out; +} + +BOOST_AUTO_TEST_CASE (check_exists) +{ + BOOST_CHECK(QFile::exists(":/test/rcc.cpp")); +} diff --git a/src/boost/tools/build/test/qt4/rcc.qrc b/src/boost/tools/build/test/qt4/rcc.qrc new file mode 100644 index 00000000..13ca38a5 --- /dev/null +++ b/src/boost/tools/build/test/qt4/rcc.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource prefix="/test/"> + <file>rcc.cpp</file> + </qresource> +</RCC> diff --git a/src/boost/tools/build/test/qt5.py b/src/boost/tools/build/test/qt5.py new file mode 100755 index 00000000..d9e1226e --- /dev/null +++ b/src/boost/tools/build/test/qt5.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +# (c) Copyright Juergen Hunold 2012 +# Use, modification, and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +# Run test in real directory in order to find Boost.Test via Boost Top-Level +# Jamroot. +qt5_dir = os.getcwd() + "/qt5" + +t = BoostBuild.Tester(workdir=qt5_dir) + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/qt5/jamroot.jam b/src/boost/tools/build/test/qt5/jamroot.jam new file mode 100644 index 00000000..78292255 --- /dev/null +++ b/src/boost/tools/build/test/qt5/jamroot.jam @@ -0,0 +1,104 @@ +# (c) Copyright Juergen Hunold 2008 +# Use, modification, and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +import qt5 ; +import testing ; +import cast ; + +path-constant CWD : . ; + + +if [ qt5.initialized ] +{ + use-project /boost : ../../../.. ; + + project qttest + : requirements + <library>/boost/test//boost_unit_test_framework + ; + + alias qt-tests : + # Check for explicit libraries, <use>/qt should not link any lib + [ link-fail qtcorefail.cpp : <use>/qt ] + + [ run qtcore.cpp /qt5//QtCore ] + [ run qtsql.cpp /qt5//QtSql ] + [ run qtxml.cpp /qt5//QtXml ] + [ run qtnetwork.cpp /qt5//QtNetwork ] + [ run qtscript.cpp /qt5//QtScript ] + [ run qtscripttools.cpp /qt5//QtScriptTools ] + [ run qtxmlpatterns.cpp /qt5//QtXmlPatterns ] + + [ run qtpositioning.cpp /qt5//QtPositioning ] + + # ToDo: runable example code + [ link qtsvg.cpp /qt5//QtSvg ] + [ link qtwidgets.cpp /qt5//QtWidgets ] + + # Multimedia toolkits. + [ link qtwebkit.cpp /qt5//QtWebKit ] + [ link qtwebkitwidgets.cpp /qt5//QtWebKitWidgets ] + [ link qtmultimedia.cpp /qt5//QtMultimedia ] + + # QtQuick version1 + [ link qtdeclarative.cpp /qt5//QtDeclarative ] + + # QtQuick version2 + [ run qtquick.cpp /qt5//QtQuick : "--" -platform offscreen : $(CWD)/qtquick.qml ] + + [ run qtwebengine.cpp /qt5//QtWebEngine ] + [ run qtwebenginewidgets.cpp /qt5//QtWebEngineWidgets ] + + # QtSerialPort + [ run qtserialport.cpp /qt5//QtSerialPort ] + + [ run qtlocation.cpp /qt5//QtLocation ] + + [ run qtwebchannel.cpp /qt5//QtWebChannel ] + [ run qtwebsockets.cpp /qt5//QtWebSockets ] + [ run qtwebview.cpp /qt5//QtWebView ] + + [ run qtpurchasing.cpp /qt5//QtPurchasing ] + + [ run qtcharts.cpp /qt5//QtCharts ] + + [ run qt3dcore.cpp /qt5//Qt3DCore ] + [ run qt3drender.cpp /qt5//Qt3DRender ] + [ run qt3dinput.cpp /qt5//Qt3DInput ] + [ run qt3dlogic.cpp /qt5//Qt3DLogic ] + + [ run qtdatavisualization.cpp /qt5//QtDataVisualization ] + + # Qt Connectivity + [ run qtbluetooth.cpp /qt5//QtBluetooth ] + [ run qtnfc.cpp /qt5//QtNfc ] + + [ run qtgamepad.cpp /qt5//QtGamepad ] + + [ run qtscxml.cpp /qt5//QtScxml ] + + [ run qtserialbus.cpp /qt5//QtSerialBus ] + + + # Help systems. + [ link qthelp.cpp /qt5//QtHelp ] + + # Testing using QtTest. Simple sample + # ToDo: better support for "automoc" aka '#include "qttest.moc"' + [ run qttest.cpp [ cast _ moccable5-cpp : qttest.cpp ] /qt5//QtTest : : : <define>TEST_MOCK ] + + # Test moc rule + [ run mock.cpp mock.h /qt5//QtCore : : : <define>TEST_MOCK ] + + # Test resource compiler + [ run rcc.cpp rcc.qrc /qt5//QtCore : : : <rccflags>"-compress 9 -threshold 10" ] + + : # requirements + : # default-build + : # usage-requirements + ; +} + + diff --git a/src/boost/tools/build/test/qt5/mock.cpp b/src/boost/tools/build/test/qt5/mock.cpp new file mode 100644 index 00000000..82fc608d --- /dev/null +++ b/src/boost/tools/build/test/qt5/mock.cpp @@ -0,0 +1,26 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtMoc + +#include "mock.h" + +#include <boost/test/unit_test.hpp> + +Mock::Mock() +{ +} + +/*! + Check that the compiler get the correct #defines. + The logic to test the moc is in the header file "mock.h" + */ +BOOST_AUTO_TEST_CASE(construct_mock) +{ + delete new Mock(); + + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(TEST_MOCK), true); +} diff --git a/src/boost/tools/build/test/qt5/mock.h b/src/boost/tools/build/test/qt5/mock.h new file mode 100644 index 00000000..eac177d4 --- /dev/null +++ b/src/boost/tools/build/test/qt5/mock.h @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <QtCore/QObject> + +class Mock : public QObject +{ + /*! + Test that the moc gets the necessary #defines + Else the moc will not see the Q_OBJECT macro, issue a warning + and linking will fail due to missing vtable symbols. + */ +#if defined(TEST_MOCK) + Q_OBJECT +#endif + public: + + Mock(); +}; diff --git a/src/boost/tools/build/test/qt5/qt3dcore.cpp b/src/boost/tools/build/test/qt5/qt3dcore.cpp new file mode 100644 index 00000000..9d1871bd --- /dev/null +++ b/src/boost/tools/build/test/qt5/qt3dcore.cpp @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2015 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE Qt3DCore +#include <Qt3DCore> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DCORE_LIB), true); +} + +BOOST_AUTO_TEST_CASE ( sample_code ) +{ + Qt3DCore::QTransform torusTransform; + torusTransform.setScale3D(QVector3D(1.5, 1, 0.5)); + torusTransform.setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 45.0f)); +} diff --git a/src/boost/tools/build/test/qt5/qt3dinput.cpp b/src/boost/tools/build/test/qt5/qt3dinput.cpp new file mode 100644 index 00000000..46cee14a --- /dev/null +++ b/src/boost/tools/build/test/qt5/qt3dinput.cpp @@ -0,0 +1,24 @@ +// (c) Copyright Juergen Hunold 2015 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE Qt3DInput +#include <Qt3DInput> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DINPUT_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DCORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DRENDER_LIB), true); +} + + +BOOST_AUTO_TEST_CASE ( sample_code ) +{ + Qt3DCore::QEntity rootEntity; + +} + diff --git a/src/boost/tools/build/test/qt5/qt3dlogic.cpp b/src/boost/tools/build/test/qt5/qt3dlogic.cpp new file mode 100644 index 00000000..088f4209 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qt3dlogic.cpp @@ -0,0 +1,20 @@ +// (c) Copyright Juergen Hunold 2015 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE Qt3DLogic +#include <Qt3DLogic> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DCORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DLOGIC_LIB), true); +} + +BOOST_AUTO_TEST_CASE ( sample_code ) +{ + Qt3DLogic::QLogicAspect logicAspect; +} diff --git a/src/boost/tools/build/test/qt5/qt3drender.cpp b/src/boost/tools/build/test/qt5/qt3drender.cpp new file mode 100644 index 00000000..d4578054 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qt3drender.cpp @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2015 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE Qt3DRender +#include <Qt3DRender> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DCORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_3DRENDER_LIB), true); +} + +BOOST_AUTO_TEST_CASE ( sample_code ) +{ + Qt3DCore::QEntity rootEntity; + Qt3DRender::QMaterial material(&rootEntity); +} diff --git a/src/boost/tools/build/test/qt5/qtassistant.cpp b/src/boost/tools/build/test/qt5/qtassistant.cpp new file mode 100644 index 00000000..c15ee4ec --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtassistant.cpp @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtAssistant + +#include <QAssistantClient> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); +} + +BOOST_AUTO_TEST_CASE( empty_assistant) +{ + QAssistantClient client(QString()); +} diff --git a/src/boost/tools/build/test/qt5/qtbluetooth.cpp b/src/boost/tools/build/test/qt5/qtbluetooth.cpp new file mode 100644 index 00000000..53beff17 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtbluetooth.cpp @@ -0,0 +1,34 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtBluetooth + +#include <QtBluetooth> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_BLUETOOTH_LIB), true); +} + +/*! + Try to detect a device + */ +BOOST_AUTO_TEST_CASE( bluetooth ) +{ + QList<QBluetoothHostInfo> localAdapters = QBluetoothLocalDevice::allDevices(); + + if (!localAdapters.empty()) + { + QBluetoothLocalDevice adapter(localAdapters.at(0).address()); + adapter.setHostMode(QBluetoothLocalDevice::HostDiscoverable); + } + else + { + BOOST_TEST(localAdapters.size() == 0); + } +} diff --git a/src/boost/tools/build/test/qt5/qtcharts.cpp b/src/boost/tools/build/test/qt5/qtcharts.cpp new file mode 100644 index 00000000..d29c4fd0 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtcharts.cpp @@ -0,0 +1,15 @@ +// (c) Copyright Juergen Hunold 2015 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCharts +#include <QtCharts> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WIDGETS_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CHARTS_LIB), true); +} diff --git a/src/boost/tools/build/test/qt5/qtcore.cpp b/src/boost/tools/build/test/qt5/qtcore.cpp new file mode 100644 index 00000000..6a2c62c8 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtcore.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCore +#include <QtCore> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( qstring_test) +{ + QString dummy; + + BOOST_CHECK_EQUAL(dummy.isEmpty(), true); +} diff --git a/src/boost/tools/build/test/qt5/qtcorefail.cpp b/src/boost/tools/build/test/qt5/qtcorefail.cpp new file mode 100644 index 00000000..8032d47c --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtcorefail.cpp @@ -0,0 +1,23 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCoreFail + +#include <QtCore> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( qstring_test) +{ + QString dummy; + + BOOST_CHECK_EQUAL(dummy.isEmpty(), true); +} diff --git a/src/boost/tools/build/test/qt5/qtdatavisualization.cpp b/src/boost/tools/build/test/qt5/qtdatavisualization.cpp new file mode 100644 index 00000000..bc35c04c --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtdatavisualization.cpp @@ -0,0 +1,31 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtDataVisualization + +#include <QtDataVisualization> + +#include <QGuiApplication> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_DATAVISUALIZATION_LIB), true); +} + +BOOST_AUTO_TEST_CASE( datavisualization ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QtDataVisualization::Q3DBars graph; + + graph.setShadowQuality(QtDataVisualization::QAbstract3DGraph::ShadowQualitySoftMedium); + graph.activeTheme()->setBackgroundEnabled(false); + graph.activeTheme()->setLabelBackgroundEnabled(true); +} diff --git a/src/boost/tools/build/test/qt5/qtdeclarative.cpp b/src/boost/tools/build/test/qt5/qtdeclarative.cpp new file mode 100644 index 00000000..df70f5e4 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtdeclarative.cpp @@ -0,0 +1,26 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtDeclarative + +#include <QCoreApplication> +#include <QDeclarativeView> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_DECLARATIVE_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( declarative ) +{ + QCoreApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + QDeclarativeView view; +} diff --git a/src/boost/tools/build/test/qt5/qtgamepad.cpp b/src/boost/tools/build/test/qt5/qtgamepad.cpp new file mode 100644 index 00000000..c6c6aea5 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtgamepad.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtGamepad + +#include <QtGamepad> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GAMEPAD_LIB), true); +} + +/*! + Try to detect a device + */ +BOOST_AUTO_TEST_CASE( gamepad ) +{ + auto gamepads = QGamepadManager::instance()->connectedGamepads(); + if (gamepads.isEmpty()) { + return; + } + + QGamepad gamepad(*gamepads.begin()); +} diff --git a/src/boost/tools/build/test/qt5/qthelp.cpp b/src/boost/tools/build/test/qt5/qthelp.cpp new file mode 100644 index 00000000..b0e877a6 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qthelp.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtHelp + +#include <QtHelp> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); +} + +BOOST_AUTO_TEST_CASE( empty_engine) +{ + QHelpEngine engine(QString()); +} diff --git a/src/boost/tools/build/test/qt5/qtlocation.cpp b/src/boost/tools/build/test/qt5/qtlocation.cpp new file mode 100644 index 00000000..9806dca9 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtlocation.cpp @@ -0,0 +1,30 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtPositioning + +#include <QGeoAddress> +#include <QGeoLocation> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_POSITIONING_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_NETWORK_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_LOCATION_LIB), true); +} + +BOOST_TEST_DONT_PRINT_LOG_VALUE(QGeoAddress) + +BOOST_AUTO_TEST_CASE( geo_location ) +{ + QGeoLocation geolocation; + + QGeoAddress address; + + BOOST_CHECK_EQUAL(geolocation.address(), address); +} diff --git a/src/boost/tools/build/test/qt5/qtmultimedia.cpp b/src/boost/tools/build/test/qt5/qtmultimedia.cpp new file mode 100644 index 00000000..dc5914af --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtmultimedia.cpp @@ -0,0 +1,25 @@ +// (c) Copyright Juergen Hunold 2009 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtMultimedia + +#include <QAudioDeviceInfo> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_MULTIMEDIA_LIB), true); +} + +BOOST_AUTO_TEST_CASE( audiodevices) +{ + QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + for(int i = 0; i < devices.size(); ++i) { + BOOST_TEST_MESSAGE(QAudioDeviceInfo(devices.at(i)).deviceName().constData()); + } +} diff --git a/src/boost/tools/build/test/qt5/qtnetwork.cpp b/src/boost/tools/build/test/qt5/qtnetwork.cpp new file mode 100644 index 00000000..d3424668 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtnetwork.cpp @@ -0,0 +1,33 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtNetwork + +#include <QHostInfo> + +#include <QTextStream> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_NETWORK_LIB), true); +} + +BOOST_AUTO_TEST_CASE( hostname ) +{ + QHostInfo info(QHostInfo::fromName("www.boost.org")); //blocking lookup + + QTextStream stream(stdout, QIODevice::WriteOnly); + + Q_FOREACH(QHostAddress address, info.addresses()) + { + BOOST_CHECK_EQUAL(address.isNull(), false); + stream << address.toString() << endl; + } +} diff --git a/src/boost/tools/build/test/qt5/qtnfc.cpp b/src/boost/tools/build/test/qt5/qtnfc.cpp new file mode 100644 index 00000000..df3805f6 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtnfc.cpp @@ -0,0 +1,28 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtNfc + +#include <QtNfc> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_NFC_LIB), true); +} + +/*! + Try to detect a device + */ +BOOST_AUTO_TEST_CASE( nfc ) +{ + QNearFieldManager manager; + if (!manager.isAvailable()) + { + BOOST_TEST_MESSAGE("No Nfc"); + } +} diff --git a/src/boost/tools/build/test/qt5/qtpositioning.cpp b/src/boost/tools/build/test/qt5/qtpositioning.cpp new file mode 100644 index 00000000..427b41ba --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtpositioning.cpp @@ -0,0 +1,23 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtPositioning + +#include <QGeoCoordinate> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_POSITIONING_LIB), true); +} + +BOOST_AUTO_TEST_CASE( geo_coordinate ) +{ + QGeoCoordinate geocoordinate; + + BOOST_CHECK_EQUAL(geocoordinate.type(), QGeoCoordinate::InvalidCoordinate); +} diff --git a/src/boost/tools/build/test/qt5/qtpurchasing.cpp b/src/boost/tools/build/test/qt5/qtpurchasing.cpp new file mode 100644 index 00000000..9a49ed2c --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtpurchasing.cpp @@ -0,0 +1,44 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtPurchasing + +#include <QtPurchasing> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_PURCHASING_LIB), true); +} + +class DummyProduct : public QInAppProduct +{ +public: + + DummyProduct() : QInAppProduct{QStringLiteral("One"), + QString{}, + QString{}, + Consumable, + QStringLiteral("DummyProduct"), + nullptr} {}; + void purchase() override {}; +}; + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +BOOST_AUTO_TEST_CASE (purchase) +{ + DummyProduct product; + + BOOST_TEST(product.price() == QLatin1String("One")); + BOOST_TEST(product.identifier() == QLatin1String("DummyProduct")); +} diff --git a/src/boost/tools/build/test/qt5/qtquick.cpp b/src/boost/tools/build/test/qt5/qtquick.cpp new file mode 100644 index 00000000..bec0d809 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtquick.cpp @@ -0,0 +1,43 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtQuick +#include <QDir> +#include <QTimer> +#include <QGuiApplication> +#include <QQmlEngine> +#include <QQuickView> +#include <QDebug> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_QML_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_QUICK_LIB), true); +} + +BOOST_AUTO_TEST_CASE (simple_test) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + QQuickView view; + + QString fileName(boost::unit_test::framework::master_test_suite().argv[1]); + + view.connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit())); + view.setSource(QUrl::fromLocalFile(fileName)); \ + + QTimer::singleShot(2000, &app, SLOT(quit())); // Auto-close window + + if (QGuiApplication::platformName() == QLatin1String("qnx") || + QGuiApplication::platformName() == QLatin1String("eglfs")) { + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.showFullScreen(); + } else { + view.show(); + } + BOOST_CHECK_EQUAL(app.exec(), 0); +} diff --git a/src/boost/tools/build/test/qt5/qtquick.qml b/src/boost/tools/build/test/qt5/qtquick.qml new file mode 100644 index 00000000..8defc050 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtquick.qml @@ -0,0 +1,20 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +import QtQuick 2.0 + +Rectangle { + id: page + width: 400; height: 200 + color: "#d6d6d6" + Text { + id: helloText + text: "Boost.Build built!" + color: "darkgray" + anchors.horizontalCenter: page.horizontalCenter + anchors.verticalCenter: page.verticalCenter + font.pointSize: 30; font.italic: true ; font.bold: true + } +} diff --git a/src/boost/tools/build/test/qt5/qtscript.cpp b/src/boost/tools/build/test/qt5/qtscript.cpp new file mode 100644 index 00000000..d48c073e --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtscript.cpp @@ -0,0 +1,37 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtScript + +#include <QScriptEngine> + +#include <QCoreApplication> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SCRIPT_LIB), true); +} + +BOOST_AUTO_TEST_CASE( script ) +{ + QCoreApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + QScriptEngine myEngine; + QScriptValue three = myEngine.evaluate("1 + 2"); + + BOOST_CHECK_EQUAL(three.toNumber(), 3); + BOOST_CHECK_EQUAL(three.toString(), QLatin1String("3")); +} diff --git a/src/boost/tools/build/test/qt5/qtscripttools.cpp b/src/boost/tools/build/test/qt5/qtscripttools.cpp new file mode 100644 index 00000000..002056a0 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtscripttools.cpp @@ -0,0 +1,47 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtScriptTools + +#include <QScriptEngine> + +#include <QScriptEngineDebugger> + +#include <QCoreApplication> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +namespace utf = boost::unit_test::framework; + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SCRIPTTOOLS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( script ) +{ + QCoreApplication app(utf::master_test_suite().argc, + utf::master_test_suite().argv); + + QScriptEngine myEngine; + QScriptValue three = myEngine.evaluate("1 + 2"); + + QScriptEngineDebugger debugger; + debugger.attachTo(&myEngine); + + BOOST_CHECK_EQUAL(three.toNumber(), 3); + BOOST_CHECK_EQUAL(three.toString(), QLatin1String("3")); + + debugger.detach(); +} diff --git a/src/boost/tools/build/test/qt5/qtscxml.cpp b/src/boost/tools/build/test/qt5/qtscxml.cpp new file mode 100644 index 00000000..9e423a18 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtscxml.cpp @@ -0,0 +1,33 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtScxml + +#include <QtScxml> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SCXML_LIB), true); +} + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +/*! + */ +BOOST_AUTO_TEST_CASE( scxml ) +{ + QString sessionId = QScxmlStateMachine::generateSessionId(QStringLiteral("dummy")); + + BOOST_TEST(sessionId.isEmpty() == false); + BOOST_TEST(sessionId == QString{"dummy1"}); +} diff --git a/src/boost/tools/build/test/qt5/qtserialbus.cpp b/src/boost/tools/build/test/qt5/qtserialbus.cpp new file mode 100644 index 00000000..5849351d --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtserialbus.cpp @@ -0,0 +1,25 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtSerialBus + +#include <QtSerialBus> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SERIALBUS_LIB), true); +} + +/*! + create a canbus instance + */ +BOOST_AUTO_TEST_CASE( serialBus ) +{ + auto canbus = QCanBus::instance(); + Q_UNUSED(canbus); +} diff --git a/src/boost/tools/build/test/qt5/qtserialport.cpp b/src/boost/tools/build/test/qt5/qtserialport.cpp new file mode 100644 index 00000000..fd24ed92 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtserialport.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtSerialPort + +#include <QtSerialPort> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SERIALPORT_LIB), true); +} + +BOOST_AUTO_TEST_CASE( serialport ) +{ + QSerialPort serialPort; + serialPort.setPortName(QStringLiteral("test serialport")); +} diff --git a/src/boost/tools/build/test/qt5/qtsql.cpp b/src/boost/tools/build/test/qt5/qtsql.cpp new file mode 100644 index 00000000..127c5a3f --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtsql.cpp @@ -0,0 +1,37 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtSql + +#include <QSqlDatabase> + +#include <QTextStream> +#include <QStringList> + +#include <boost/test/unit_test.hpp> + +#include <iostream> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SQL_LIB), true); +} + +BOOST_AUTO_TEST_CASE( drivers ) +{ + QTextStream stream(stdout, QIODevice::WriteOnly); + + Q_FOREACH(QString it, QSqlDatabase:: drivers()) + { + stream << it << endl; + } +} + +BOOST_AUTO_TEST_CASE( construct ) +{ + QSqlDatabase database; + BOOST_CHECK_EQUAL(database.isOpen(), false); +} diff --git a/src/boost/tools/build/test/qt5/qtsvg.cpp b/src/boost/tools/build/test/qt5/qtsvg.cpp new file mode 100644 index 00000000..ccfd6b4d --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtsvg.cpp @@ -0,0 +1,21 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtSvg + +#include <QtSvg> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SVG_LIB), true); +} + +BOOST_AUTO_TEST_CASE( generator_construct) +{ + QSvgGenerator generator; +} diff --git a/src/boost/tools/build/test/qt5/qttest.cpp b/src/boost/tools/build/test/qt5/qttest.cpp new file mode 100644 index 00000000..ddc8f686 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qttest.cpp @@ -0,0 +1,30 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <QtTest> + +class QtTest: public QObject +{ + /*! + Test if the moc gets the #define + */ +#if defined(TEST_MOCK) + Q_OBJECT +#endif + +private Q_SLOTS: + void toUpper(); +}; + +void +QtTest::toUpper() +{ + QString str = "Hello"; + QCOMPARE(str.toUpper(), QString("HELLO")); +} + +QTEST_MAIN(QtTest) +#include "qttest.moc" + diff --git a/src/boost/tools/build/test/qt5/qtwebchannel.cpp b/src/boost/tools/build/test/qt5/qtwebchannel.cpp new file mode 100644 index 00000000..e4f05b7f --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebchannel.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebChannel + +#include <QtWebChannel> + +#include <QGuiApplication> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBCHANNEL_LIB), true); +} + +BOOST_AUTO_TEST_CASE( webchannel ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QWebChannel channel; + QObject dummy; + channel.registerObject(QStringLiteral("dummy"), &dummy); +} diff --git a/src/boost/tools/build/test/qt5/qtwebengine.cpp b/src/boost/tools/build/test/qt5/qtwebengine.cpp new file mode 100644 index 00000000..d4c1b072 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebengine.cpp @@ -0,0 +1,30 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebEngine + +#include <QtWebEngine> +#include <QGuiApplication> + + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINE_LIB), true); +} + +/*! + Just call the global initialization function + */ +BOOST_AUTO_TEST_CASE( webengine ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QtWebEngine::initialize(); +} diff --git a/src/boost/tools/build/test/qt5/qtwebenginewidgets.cpp b/src/boost/tools/build/test/qt5/qtwebenginewidgets.cpp new file mode 100644 index 00000000..f0c3c2d8 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebenginewidgets.cpp @@ -0,0 +1,40 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebEngineWidgets + +#include <QtWebEngineWidgets> + +#include <QWebEngineProfile> +#include <QWebEngineSettings> +#include <QWebEngineScript> + +#include <QApplication> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WIDGETS_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINECORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINEWIDGETS_LIB), true); +} + +/*! + Also tests the core library + */ +BOOST_AUTO_TEST_CASE( webengine_widgets ) +{ + QApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); + QWebEngineProfile *defaultProfile = QWebEngineProfile::defaultProfile(); + + defaultSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); + defaultProfile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); +} diff --git a/src/boost/tools/build/test/qt5/qtwebkit.cpp b/src/boost/tools/build/test/qt5/qtwebkit.cpp new file mode 100644 index 00000000..aa6fdc92 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebkit.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebKit + +#include <QWebSettings> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBKIT_LIB), true); +} + +BOOST_AUTO_TEST_CASE( webkit ) +{ + BOOST_CHECK(QWebSettings::globalSettings()); +} diff --git a/src/boost/tools/build/test/qt5/qtwebkitwidgets.cpp b/src/boost/tools/build/test/qt5/qtwebkitwidgets.cpp new file mode 100644 index 00000000..52c05c9a --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebkitwidgets.cpp @@ -0,0 +1,23 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebKitWidgets + +#include <QWebPage> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBKITWIDGETS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( webkit ) +{ + QWebPage page; + BOOST_CHECK_EQUAL(page.isModified(), false); +} diff --git a/src/boost/tools/build/test/qt5/qtwebsocket.cpp b/src/boost/tools/build/test/qt5/qtwebsocket.cpp new file mode 100644 index 00000000..f46aa58b --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebsocket.cpp @@ -0,0 +1,26 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebSockets + +#include <QtWebSockets> + +#include <QCoreApplication> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBSOCKETS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( websocket ) +{ + QCoreApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QWebSocket socket; +} diff --git a/src/boost/tools/build/test/qt5/qtwebsockets.cpp b/src/boost/tools/build/test/qt5/qtwebsockets.cpp new file mode 100644 index 00000000..9829ce91 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebsockets.cpp @@ -0,0 +1,24 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebSockets + +#include <QtWebSockets> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBSOCKETS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( websocket ) +{ + QWebSocket socket; + socket.setPauseMode(QAbstractSocket::PauseNever); + + BOOST_TEST(socket.isValid() == false); +} diff --git a/src/boost/tools/build/test/qt5/qtwebview.cpp b/src/boost/tools/build/test/qt5/qtwebview.cpp new file mode 100644 index 00000000..dfd130f3 --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwebview.cpp @@ -0,0 +1,31 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtWebView + +#include <QtWebView> + +#include <QGuiApplication> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINECORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBVIEW_LIB), true); +} + +/*! + Just call the global initialization function + */ +BOOST_AUTO_TEST_CASE( webview ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QtWebView::initialize(); +} diff --git a/src/boost/tools/build/test/qt5/qtwidgets.cpp b/src/boost/tools/build/test/qt5/qtwidgets.cpp new file mode 100644 index 00000000..b868240a --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtwidgets.cpp @@ -0,0 +1,43 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtGui + +#include <QtWidgets/QApplication> + +#include <boost/test/unit_test.hpp> + +struct Fixture +{ + Fixture() + : application(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv, + false) + { + BOOST_TEST_MESSAGE( "setup QApplication fixture" ); + } + + ~Fixture() + { + BOOST_TEST_MESSAGE( "teardown QApplication fixture" ); + } + + QApplication application; +}; + +BOOST_GLOBAL_FIXTURE( Fixture ); + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WIDGETS_LIB), true); +} + + +BOOST_AUTO_TEST_CASE( qtgui_test) +{ + BOOST_CHECK_EQUAL(true, true); +} diff --git a/src/boost/tools/build/test/qt5/qtxml.cpp b/src/boost/tools/build/test/qt5/qtxml.cpp new file mode 100644 index 00000000..3df6dd2c --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtxml.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtXml + +#include <QtXml> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), true); +} + +BOOST_AUTO_TEST_CASE( reader_construct) +{ + QXmlStreamReader reader; + BOOST_CHECK_EQUAL(reader.atEnd(), false); +} + +BOOST_AUTO_TEST_CASE( writer_construct) +{ + QXmlStreamWriter writer; + BOOST_CHECK_EQUAL(writer.device(), static_cast<QIODevice*>(0)); +} + diff --git a/src/boost/tools/build/test/qt5/qtxmlpatterns.cpp b/src/boost/tools/build/test/qt5/qtxmlpatterns.cpp new file mode 100644 index 00000000..d87e3d3f --- /dev/null +++ b/src/boost/tools/build/test/qt5/qtxmlpatterns.cpp @@ -0,0 +1,76 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtXmlPatterns + +#include <QXmlQuery> +#include <QXmlSerializer> + +#include <QCoreApplication> +#include <QString> +#include <QTextStream> +#include <QBuffer> + +#include <boost/test/unit_test.hpp> + + +struct Fixture +{ + Fixture() + : application(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv) + { + BOOST_TEST_MESSAGE( "setup QCoreApplication fixture" ); + } + + ~Fixture() + { + BOOST_TEST_MESSAGE( "teardown QCoreApplication fixture" ); + } + + QCoreApplication application; +}; + +BOOST_GLOBAL_FIXTURE( Fixture ); + +QByteArray doc("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<html xmlns=\"http://www.w3.org/1999/xhtml/\" xml:lang=\"en\" lang=\"en\">" +" <head>" +" <title>Global variables report for globals.gccxml</title>" +" </head>" +"<body><p>Some Test text</p></body></html>"); + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XMLPATTERNS_LIB), true); + + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_XML_LIB), false); +} + +BOOST_AUTO_TEST_CASE( extract ) +{ + + QBuffer buffer(&doc); // This is a QIODevice. + buffer.open(QIODevice::ReadOnly); + QXmlQuery query; + query.bindVariable("myDocument", &buffer); + query.setQuery("declare variable $myDocument external;" + "doc($myDocument)");///p[1]"); + + BOOST_CHECK_EQUAL(query.isValid(), true); + + QByteArray result; + QBuffer out(&result); + out.open(QIODevice::WriteOnly); + + QXmlSerializer serializer(query, &out); + BOOST_CHECK_EQUAL(query.evaluateTo(&serializer), true); + + QTextStream stream(stdout); + BOOST_CHECK_EQUAL(result.isEmpty(), false); + stream << "hallo" << result << endl; +} + diff --git a/src/boost/tools/build/test/qt5/rcc.cpp b/src/boost/tools/build/test/qt5/rcc.cpp new file mode 100644 index 00000000..cae553bb --- /dev/null +++ b/src/boost/tools/build/test/qt5/rcc.cpp @@ -0,0 +1,20 @@ +// (c) Copyright Juergen Hunold 2012 +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_TEST_MODULE QtCore +#include <QtCore> + +#include <boost/test/unit_test.hpp> + +std::ostream& operator<<(std::ostream& out, QString const& text) +{ + out << text.toUtf8().constData(); + return out; +} + +BOOST_AUTO_TEST_CASE (check_exists) +{ + BOOST_CHECK(QFile::exists(":/test/rcc.cpp")); +} diff --git a/src/boost/tools/build/test/qt5/rcc.qrc b/src/boost/tools/build/test/qt5/rcc.qrc new file mode 100644 index 00000000..13ca38a5 --- /dev/null +++ b/src/boost/tools/build/test/qt5/rcc.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> + <qresource prefix="/test/"> + <file>rcc.cpp</file> + </qresource> +</RCC> diff --git a/src/boost/tools/build/test/railsys.py b/src/boost/tools/build/test/railsys.py new file mode 100644 index 00000000..7b7f8bd0 --- /dev/null +++ b/src/boost/tools/build/test/railsys.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester() + +t.set_tree("railsys") +t.run_build_system("--v2", subdir="program") + +t.cleanup() diff --git a/src/boost/tools/build/test/railsys/libx/include/test_libx.h b/src/boost/tools/build/test/railsys/libx/include/test_libx.h new file mode 100644 index 00000000..fe573fc1 --- /dev/null +++ b/src/boost/tools/build/test/railsys/libx/include/test_libx.h @@ -0,0 +1,25 @@ +// Copyright (c) 2003 Institute of Transport, +// Railway Construction and Operation, +// University of Hanover, Germany +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef _WIN32 +#ifdef LIBX_SOURCE +__declspec(dllexport) +#else +__declspec(dllimport) +#endif +#endif +class TestLibX +{ +public: + + TestLibX(); + + // Needed to suppress 'unused variable' warning + // in some cases. + void do_something() {} +}; diff --git a/src/boost/tools/build/test/railsys/libx/jamroot.jam b/src/boost/tools/build/test/railsys/libx/jamroot.jam new file mode 100644 index 00000000..d09982dd --- /dev/null +++ b/src/boost/tools/build/test/railsys/libx/jamroot.jam @@ -0,0 +1,13 @@ +# Copyright (c) 2002 Institute of Transport, +# Railway Construction and Operation, +# University of Hanover, Germany +# Copyright (c) 2006 Jürgen Hunold +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tell that Qt3 should be used. QTDIR will give installation prefix. +using qt3 ; + + diff --git a/src/boost/tools/build/test/railsys/libx/src/jamfile.jam b/src/boost/tools/build/test/railsys/libx/src/jamfile.jam new file mode 100644 index 00000000..639e0cc9 --- /dev/null +++ b/src/boost/tools/build/test/railsys/libx/src/jamfile.jam @@ -0,0 +1,19 @@ +# Copyright (c) 2003 Institute of Transport, +# Railway Construction and Operation, +# University of Hanover, Germany +# +# Copyright (c) 2006 Jürgen Hunold +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project libx + : requirements + <include>../include + : usage-requirements + <include>../include + ; + + +lib libx : test_libx.cpp ; diff --git a/src/boost/tools/build/test/railsys/libx/src/test_libx.cpp b/src/boost/tools/build/test/railsys/libx/src/test_libx.cpp new file mode 100644 index 00000000..be1fbc27 --- /dev/null +++ b/src/boost/tools/build/test/railsys/libx/src/test_libx.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2003 Institute of Transport, +// Railway Construction and Operation, +// University of Hanover, Germany +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#define LIBX_SOURCE +#include <test_libx.h> + +TestLibX::TestLibX() +{ +} diff --git a/src/boost/tools/build/test/railsys/program/include/test_a.h b/src/boost/tools/build/test/railsys/program/include/test_a.h new file mode 100644 index 00000000..8002859e --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/include/test_a.h @@ -0,0 +1,22 @@ +// Copyright (c) 2003 Institute of Transport, +// Railway Construction and Operation, +// University of Hanover, Germany +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#include <qobject.h> + +class TestA : public QObject +{ + Q_OBJECT + +public: + + TestA(); + + // Needed to suppress 'unused variable' varning. + void do_something() { } +}; diff --git a/src/boost/tools/build/test/railsys/program/jamfile.jam b/src/boost/tools/build/test/railsys/program/jamfile.jam new file mode 100644 index 00000000..9e36f408 --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/jamfile.jam @@ -0,0 +1,45 @@ +# ================================================================ +# +# Railsys +# -------------- +# +# Copyright (c) 2002 Institute of Transport, +# Railway Construction and Operation, +# University of Hanover, Germany +# Copyright (c) 2006 Jürgen Hunold +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# +# 02/21/02! Jürgen Hunold +# +# $Id$ +# +# ================================================================ + +local BOOST_ROOT = [ modules.peek : BOOST_ROOT ] ; + +use-project /libx : ../libx/src ; + +project program + : requirements + <include>$(BOOST_ROOT) + <threading>multi + <library>/qt3//qt + <hardcode-dll-paths>true + <stdlib>stlport + <use>/libx + <library>/libx//libx + + : usage-requirements + <include>$(BOOST_ROOT) + : + default-build release + <threading>multi + <library>/qt3//qt + <hardcode-dll-paths>true + ; + +build-project main ; + diff --git a/src/boost/tools/build/test/railsys/program/jamroot.jam b/src/boost/tools/build/test/railsys/program/jamroot.jam new file mode 100644 index 00000000..23d42195 --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/jamroot.jam @@ -0,0 +1,14 @@ +# Copyright (c) 2002 Institute of Transport, +# Railway Construction and Operation, +# University of Hanover, Germany +# Copyright (c) 2006 Jürgen Hunold +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tell that Qt3 should be used. QTDIR will give installation prefix. +using qt3 ; + +# Not that good, but sufficient for testing +using stlport : : /path/to/stlport ; diff --git a/src/boost/tools/build/test/railsys/program/liba/jamfile.jam b/src/boost/tools/build/test/railsys/program/liba/jamfile.jam new file mode 100644 index 00000000..f74311d0 --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/liba/jamfile.jam @@ -0,0 +1,14 @@ +# Copyright (c) 2003 Institute of Transport, +# Railway Construction and Operation, +# University of Hanover, Germany +# Copyright (c) 2006 Jürgen Hunold +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project liba ; + +lib liba : test ../include/test_a.h ; + +obj test : test_a.cpp : <optimization>off ; diff --git a/src/boost/tools/build/test/railsys/program/liba/test_a.cpp b/src/boost/tools/build/test/railsys/program/liba/test_a.cpp new file mode 100644 index 00000000..f9e53885 --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/liba/test_a.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2003 Institute of Transport, +// Railway Construction and Operation, +// University of Hanover, Germany +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "../include/test_a.h" + +#include <test_libx.h> + +TestA::TestA() +{ + TestLibX aTestLibX; + aTestLibX.do_something(); +} diff --git a/src/boost/tools/build/test/railsys/program/main/jamfile.jam b/src/boost/tools/build/test/railsys/program/main/jamfile.jam new file mode 100644 index 00000000..095978ea --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/main/jamfile.jam @@ -0,0 +1,12 @@ +# Copyright (c) 2002 Institute of Transport, +# Railway Construction and Operation, +# University of Hanover, Germany +# Copyright (c) 2006 Jürgen Hunold +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project main ; + +exe test_a : main.cpp ../liba//liba /libx ; diff --git a/src/boost/tools/build/test/railsys/program/main/main.cpp b/src/boost/tools/build/test/railsys/program/main/main.cpp new file mode 100644 index 00000000..3f13f4bf --- /dev/null +++ b/src/boost/tools/build/test/railsys/program/main/main.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2002 Institute of Transport, +// Railway Construction and Operation, +// University of Hanover, Germany +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "../include/test_a.h" + +#include <test_libx.h> + +int main() +{ + TestLibX stTestLibX; + TestA stTestA; + + stTestLibX.do_something(); +}; diff --git a/src/boost/tools/build/test/readme.txt b/src/boost/tools/build/test/readme.txt new file mode 100644 index 00000000..48459f80 --- /dev/null +++ b/src/boost/tools/build/test/readme.txt @@ -0,0 +1,6 @@ +# Copyright 2002 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + See test_system.html for detailed information on using the Boost Build test +system. diff --git a/src/boost/tools/build/test/rebuilds.py b/src/boost/tools/build/test/rebuilds.py new file mode 100644 index 00000000..8242e3ec --- /dev/null +++ b/src/boost/tools/build/test/rebuilds.py @@ -0,0 +1,68 @@ +#!/usr/bin/python + +# Copyright 2005 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + + +def wait_for_bar(t): + """ + Wait to make the test system correctly recognize the 'bar' file as + touched after the next build run. Without the wait, the next build run may + rebuild the 'bar' file with the new and the old file modification timestamp + too close to each other - which could, depending on the currently supported + file modification timestamp resolution, be detected as 'no change' by the + testing system. + + """ + t.wait_for_time_change("bar", touch=False) + + +t = BoostBuild.Tester(["-ffile.jam", "-d+3", "-d+12", "-d+13"], + pass_toolset=0) + +t.write("file.jam", """\ +rule make +{ + DEPENDS $(<) : $(>) ; + DEPENDS all : $(<) ; +} +actions make +{ + echo "******" making $(<) from $(>) "******" + echo made from $(>) > $(<) +} + +make aux1 : bar ; +make foo : bar ; +REBUILDS foo : bar ; +make bar : baz ; +make aux2 : bar ; +""") + +t.write("baz", "nothing") + +t.run_build_system(["bar"]) +t.expect_addition("bar") +t.expect_nothing_more() + +wait_for_bar(t) +t.run_build_system(["foo"]) +t.expect_touch("bar") +t.expect_addition("foo") +t.expect_nothing_more() + +t.run_build_system() +t.expect_addition(["aux1", "aux2"]) +t.expect_nothing_more() + +t.touch("bar") +wait_for_bar(t) +t.run_build_system() +t.expect_touch(["foo", "bar", "aux1", "aux2"]) +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/relative_sources.py b/src/boost/tools/build/test/relative_sources.py new file mode 100644 index 00000000..29f590fe --- /dev/null +++ b/src/boost/tools/build/test/relative_sources.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that we can specify sources using relative names. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# Test that relative path to source, 'src', is preserved. +t.write("jamroot.jam", "exe a : src/a.cpp ;") +t.write("src/a.cpp", "int main() {}\n") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/src/a.obj") + +# Test that the relative path to source is preserved +# when using 'glob'. +t.rm("bin") +t.write("jamroot.jam", "exe a : [ glob src/*.cpp ] ;") +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/src/a.obj") + + +# Test that relative path with ".." is *not* added to +# target path. +t.rm(".") +t.write("jamroot.jam", "") +t.write("a.cpp", "int main() { return 0; }\n") +t.write("build/Jamfile", "exe a : ../a.cpp ; ") +t.run_build_system(subdir="build") +t.expect_addition("build/bin/$toolset/debug*/a.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/remove_requirement.py b/src/boost/tools/build/test/remove_requirement.py new file mode 100644 index 00000000..9655ad3a --- /dev/null +++ b/src/boost/tools/build/test/remove_requirement.py @@ -0,0 +1,91 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + + +t.write("jamroot.jam", """ +project : requirements <threading>multi <variant>debug:<link>static ; +# Force link to be relevant +project : requirements <link>shared:<define>TEST_DLL ; + +build-project sub ; +build-project sub2 ; +build-project sub3 ; +build-project sub4 ; +""") + +t.write("sub/jamfile.jam", """ +exe hello : hello.cpp : -<threading>multi ; +""") + +t.write("sub/hello.cpp", """ +int main() {} +""") + +t.write("sub2/jamfile.jam", """ +project : requirements -<threading>multi ; +exe hello : hello.cpp ; +""") + +t.write("sub2/hello.cpp", """ +int main() {} +""") + +t.write("sub3/hello.cpp", """ +int main() {} +""") + +t.write("sub3/jamfile.jam", """ +exe hello : hello.cpp : "-<variant>debug:<link>static" ; +""") + +t.write("sub4/hello.cpp", """ +int main() {} +""") + +t.write("sub4/jamfile.jam", """ +project : requirements "-<variant>debug:<link>static" ; +exe hello : hello.cpp ; +""") + +t.run_build_system() + +t.expect_addition("sub/bin/$toolset/debug*/link-static*/hello.exe") +t.expect_addition("sub2/bin/$toolset/debug*/link-static*/hello.exe") +t.expect_addition("sub3/bin/$toolset/debug*/threading-multi*/hello.exe") +t.expect_addition("sub4/bin/$toolset/debug*/threading-multi*/hello.exe") + +t.rm(".") + +# Now test that path requirements can be removed as well. +t.write("jamroot.jam", """ +build-project sub ; +""") + +t.write("sub/jamfile.jam", """ +project : requirements <include>broken ; +exe hello : hello.cpp : -<include>broken ; +""") + +t.write("sub/hello.cpp", """ +#include "math.h" +int main() {} +""") + +t.write("sub/broken/math.h", """ +Broken +""") + + +t.run_build_system() + +t.expect_addition("sub/bin/$toolset/debug*/hello.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/rescan_header.py b/src/boost/tools/build/test/rescan_header.py new file mode 100755 index 00000000..1257a223 --- /dev/null +++ b/src/boost/tools/build/test/rescan_header.py @@ -0,0 +1,265 @@ +#!/usr/bin/python + +# Copyright 2012 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# Test a header loop that depends on (but does not contain) a generated header. +t.write("test.cpp", '#include "header1.h"\n') + +t.write("header1.h", """\ +#ifndef HEADER1_H +#define HEADER1_H +#include "header2.h" +#endif +""") + +t.write("header2.h", """\ +#ifndef HEADER2_H +#define HEADER2_H +#include "header1.h" +#include "header3.h" +#endif +""") + +t.write("header3.in", "/* empty file */\n") + +t.write("jamroot.jam", """\ +import common ; +make header3.h : header3.in : @common.copy ; +obj test : test.cpp : <implicit-dependency>header3.h ; +""") + +t.run_build_system(["-j2"]) +t.expect_addition("bin/header3.h") +t.expect_addition("bin/$toolset/debug*/test.obj") +t.expect_nothing_more() + +t.rm(".") + +# Test a linear sequence of generated headers. +t.write("test.cpp", '#include "header1.h"\n') + +t.write("header1.in", """\ +#ifndef HEADER1_H +#define HEADER1_H +#include "header2.h" +#endif +""") + +t.write("header2.in", """\ +#ifndef HEADER2_H +#define HEADER2_H +#include "header3.h" +#endif +""") + +t.write("header3.in", "/* empty file */\n") + +t.write("jamroot.jam", """\ +import common ; +make header1.h : header1.in : @common.copy ; +make header2.h : header2.in : @common.copy ; +make header3.h : header3.in : @common.copy ; +obj test : test.cpp : + <implicit-dependency>header1.h + <implicit-dependency>header2.h + <implicit-dependency>header3.h ; +""") + +t.run_build_system(["-j2", "test"]) +t.expect_addition("bin/header1.h") +t.expect_addition("bin/header2.h") +t.expect_addition("bin/header3.h") +t.expect_addition("bin/$toolset/debug*/test.obj") +t.expect_nothing_more() + +t.rm(".") + +# Test a loop in generated headers. +t.write("test.cpp", '#include "header1.h"\n') + +t.write("header1.in", """\ +#ifndef HEADER1_H +#define HEADER1_H +#include "header2.h" +#endif +""") + +t.write("header2.in", """\ +#ifndef HEADER2_H +#define HEADER2_H +#include "header3.h" +#endif +""") + +t.write("header3.in", """\ +#ifndef HEADER2_H +#define HEADER2_H +#include "header1.h" +#endif +""") + +t.write("jamroot.jam", """\ +import common ; + +actions copy { + sleep 1 + cp $(>) $(<) +} + +make header1.h : header1.in : @common.copy ; +make header2.h : header2.in : @common.copy ; +make header3.h : header3.in : @common.copy ; +obj test : test.cpp : + <implicit-dependency>header1.h + <implicit-dependency>header2.h + <implicit-dependency>header3.h ; +""") + +t.run_build_system(["-j2", "test"]) +t.expect_addition("bin/header1.h") +t.expect_addition("bin/header2.h") +t.expect_addition("bin/header3.h") +t.expect_addition("bin/$toolset/debug*/test.obj") +t.expect_nothing_more() + +t.rm(".") + +# Test that all the dependencies of a loop are updated before any of the +# dependents. +t.write("test1.cpp", '#include "header1.h"\n') + +t.write("test2.cpp", """\ +#include "header2.h" +int main() {} +""") + +t.write("header1.h", """\ +#ifndef HEADER1_H +#define HEADER1_H +#include "header2.h" +#endif +""") + +t.write("header2.h", """\ +#ifndef HEADER2_H +#define HEADER2_H +#include "header1.h" +#include "header3.h" +#endif +""") + +t.write("header3.in", "\n") + +t.write("sleep.bat", """\ +::@timeout /T %1 /NOBREAK >nul +@ping 127.0.0.1 -n 2 -w 1000 >nul +@ping 127.0.0.1 -n %1 -w 1000 >nul +@exit /B 0 +""") + +t.write("jamroot.jam", """\ +import common ; +import os ; + +if [ os.name ] = NT +{ + SLEEP = call sleep.bat ; +} +else +{ + SLEEP = sleep ; +} + +rule copy { common.copy $(<) : $(>) ; } +actions copy { $(SLEEP) 1 } + +make header3.h : header3.in : @copy ; +exe test : test2.cpp test1.cpp : <implicit-dependency>header3.h ; +""") + +t.run_build_system(["-j2", "test"]) +t.expect_addition("bin/header3.h") +t.expect_addition("bin/$toolset/debug*/test1.obj") +t.expect_addition("bin/$toolset/debug*/test2.obj") +t.expect_addition("bin/$toolset/debug*/test.exe") +t.expect_nothing_more() + +t.touch("header3.in") +t.run_build_system(["-j2", "test"]) +t.expect_touch("bin/header3.h") +t.expect_touch("bin/$toolset/debug*/test1.obj") +t.expect_touch("bin/$toolset/debug*/test2.obj") +t.expect_touch("bin/$toolset/debug*/test.exe") +t.expect_nothing_more() + +t.rm(".") + +# Test a loop that includes a generated header +t.write("test1.cpp", '#include "header1.h"\n') +t.write("test2.cpp", """\ +#include "header2.h" +int main() {} +""") + +t.write("header1.h", """\ +#ifndef HEADER1_H +#define HEADER1_H +#include "header2.h" +#endif +""") + +t.write("header2.in", """\ +#ifndef HEADER2_H +#define HEADER2_H +#include "header3.h" +#endif +""") + +t.write("header3.h", """\ +#ifndef HEADER3_H +#define HEADER3_H +#include "header1.h" +#endif +""") + +t.write("sleep.bat", """\ +::@timeout /T %1 /NOBREAK >nul +@ping 127.0.0.1 -n 2 -w 1000 >nul +@ping 127.0.0.1 -n %1 -w 1000 >nul +@exit /B 0 +""") + +t.write("jamroot.jam", """\ +import common ; +import os ; + +if [ os.name ] = NT +{ + SLEEP = call sleep.bat ; +} +else +{ + SLEEP = sleep ; +} + +rule copy { common.copy $(<) : $(>) ; } +actions copy { $(SLEEP) 1 } + +make header2.h : header2.in : @copy ; +exe test : test2.cpp test1.cpp : <implicit-dependency>header2.h <include>. ; +""") + +t.run_build_system(["-j2", "test"]) +t.expect_addition("bin/header2.h") +t.expect_addition("bin/$toolset/debug*/test1.obj") +t.expect_addition("bin/$toolset/debug*/test2.obj") +t.expect_addition("bin/$toolset/debug*/test.exe") +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/resolution.py b/src/boost/tools/build/test/resolution.py new file mode 100644 index 00000000..9cde218f --- /dev/null +++ b/src/boost/tools/build/test/resolution.py @@ -0,0 +1,35 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2006. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests for the target id resolution process. + +import BoostBuild + +# Create a temporary working directory. +t = BoostBuild.Tester(use_test_config=False) + +# Create the needed files +t.write("jamroot.jam", """\ +exe hello : hello.cpp ; +# This should use the 'hello' target, even if there is a 'hello' file in the +# current dir. +install s : hello : <location>. ; +""") + +t.write("hello.cpp", "int main() {}\n") + +t.run_build_system() + +t.expect_addition("bin/$toolset/debug*/hello.obj") + +t.touch("hello.cpp") +t.run_build_system(["s"]) +# If 'hello' in the 's' target resolved to file in the current dir, nothing +# will be rebuilt. +t.expect_touch("bin/$toolset/debug*/hello.obj") + +t.cleanup() diff --git a/src/boost/tools/build/test/results-python.txt b/src/boost/tools/build/test/results-python.txt new file mode 100644 index 00000000..83b351b2 --- /dev/null +++ b/src/boost/tools/build/test/results-python.txt @@ -0,0 +1,132 @@ +Note: skipping extra tests +unit_tests : FAILED +module_actions : PASSED +startup_v2 : PASSED +core_d12 : PASSED +core_typecheck : PASSED +core_delete_module : PASSED +core_language : PASSED +core_arguments : PASSED +core_varnames : PASSED +core_import_module : PASSED +absolute_sources : PASSED +alias : PASSED +alternatives : PASSED +bad_dirname : PASSED +build_dir : PASSED +build_file : PASSED +build_no : PASSED +builtin_echo : PASSED +builtin_exit : PASSED +builtin_split_by_characters : FAILED +c_file : PASSED +chain : PASSED +clean : PASSED +composite : PASSED +conditionals : PASSED +conditionals2 : PASSED +conditionals3 : PASSED +conditionals_multiple : PASSED +configuration : FAILED +copy_time : PASSED +core_action_output : PASSED +core_action_status : PASSED +core_actions_quietly : PASSED +core_at_file : PASSED +core_bindrule : PASSED +core_multifile_actions : PASSED +core_nt_cmd_line : PASSED +core_option_d2 : PASSED +core_option_l : PASSED +core_option_n : PASSED +core_parallel_actions : PASSED +core_parallel_multifile_actions_1 : PASSED +core_parallel_multifile_actions_2 : PASSED +core_source_line_tracking : PASSED +core_update_now : PASSED +core_variables_in_actions : PASSED +custom_generator : PASSED +default_build : PASSED +default_features : PASSED +dependency_property : PASSED +dependency_test : FAILED +direct_request_test : PASSED +disambiguation : PASSED +dll_path : PASSED +double_loading : PASSED +duplicate : PASSED +example_libraries : PASSED +example_make : PASSED +exit_status : PASSED +expansion : PASSED +explicit : PASSED +free_features_request : PASSED +generator_selection : FAILED +generators_test : FAILED +implicit_dependency : PASSED +indirect_conditional : FAILED +inherit_toolset : FAILED +inherited_dependency : PASSED +inline : PASSED +lib_source_property : PASSED +library_chain : PASSED +library_property : PASSED +link : FAILED +load_order : FAILED +loop : PASSED +make_rule : PASSED +message : FAILED +ndebug : PASSED +no_type : PASSED +notfile : PASSED +ordered_include : PASSED +out_of_tree : PASSED +path_features : FAILED +prebuilt : PASSED +print : FAILED +project_dependencies : PASSED +project_glob : PASSED +project_id : FAILED +project_root_constants : PASSED +project_root_rule : PASSED +project_test3 : FAILED +project_test4 : FAILED +property_expansion : PASSED +rebuilds : PASSED +regression : PASSED +relative_sources : PASSED +remove_requirement : PASSED +rescan_header : PASSED +resolution : PASSED +scanner_causing_rebuilds : FAILED +searched_lib : PASSED +skipping : PASSED +sort_rule : PASSED +source_locations : PASSED +source_order : FAILED +space_in_path : PASSED +stage : PASSED +standalone : PASSED +static_and_shared_library : PASSED +suffix : PASSED +tag : PASSED +test_result_dumping : PASSED +test_rc : FAILED +testing_support : PASSED +timedata : FAILED +unit_test : PASSED +unused : FAILED +use_requirements : PASSED +using : PASSED +wrapper : PASSED +wrong_project : PASSED +zlib : PASSED +symlink : PASSED +library_order : FAILED +gcc_runtime : FAILED +pch : PASSED + + === Test summary === + PASS: 103 + FAIL: 23 + diff --git a/src/boost/tools/build/test/rootless.py b/src/boost/tools/build/test/rootless.py new file mode 100644 index 00000000..3dc2de5b --- /dev/null +++ b/src/boost/tools/build/test/rootless.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# Copyright 2018 Rene Rivera +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +t = BoostBuild.Tester(translate_suffixes=0) + +t.set_tree("rootless/test1") +t.run_build_system(status=1) +t.expect_output_lines("error: no Jamfile in current directory*") + +t.set_tree("rootless/test1") +t.run_build_system(subdir="sub_root") +t.expect_addition("sub_root/bin/a.txt") + +t.set_tree("rootless/test1") +t.run_build_system(subdir="sub_root", extra_args=["--build-dir=../bin"]) +t.expect_output_lines("warning: the --build-dir option will be ignored") + +t.set_tree("rootless/test2") +t.run_build_system(subdir="sub_root", extra_args=["--build-dir=../bin"]) +t.expect_addition("bin/foo/a.txt") + +t.set_tree("rootless/test3") +t.run_build_system() + +t.set_tree("rootless/test3") +t.run_build_system(subdir="sub/inner") +t.expect_addition("bins/sub/inner/a.txt") + +t.cleanup() diff --git a/src/boost/tools/build/test/rootless/test1/sub_root/a.cpp b/src/boost/tools/build/test/rootless/test1/sub_root/a.cpp new file mode 100644 index 00000000..412a2bb4 --- /dev/null +++ b/src/boost/tools/build/test/rootless/test1/sub_root/a.cpp @@ -0,0 +1,6 @@ +// Copyright 2018 Rene Rivera +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +int main() {} diff --git a/src/boost/tools/build/test/rootless/test1/sub_root/jamfile.jam b/src/boost/tools/build/test/rootless/test1/sub_root/jamfile.jam new file mode 100644 index 00000000..0a17bc40 --- /dev/null +++ b/src/boost/tools/build/test/rootless/test1/sub_root/jamfile.jam @@ -0,0 +1,10 @@ +# Copyright 2018 Rene Rivera +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +actions foo +{ + echo "$(>)" > "$(<)" +} +make a.txt : a.cpp : @foo ; diff --git a/src/boost/tools/build/test/rootless/test2/sub_root/a.cpp b/src/boost/tools/build/test/rootless/test2/sub_root/a.cpp new file mode 100644 index 00000000..412a2bb4 --- /dev/null +++ b/src/boost/tools/build/test/rootless/test2/sub_root/a.cpp @@ -0,0 +1,6 @@ +// Copyright 2018 Rene Rivera +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +int main() {} diff --git a/src/boost/tools/build/test/rootless/test2/sub_root/jamfile.jam b/src/boost/tools/build/test/rootless/test2/sub_root/jamfile.jam new file mode 100644 index 00000000..62416c0b --- /dev/null +++ b/src/boost/tools/build/test/rootless/test2/sub_root/jamfile.jam @@ -0,0 +1,13 @@ +# Copyright 2018 Rene Rivera +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project foo ; + +actions foo +{ + echo "$(>)" > "$(<)" +} + +make a.txt : a.cpp : @foo ; diff --git a/src/boost/tools/build/test/rootless/test3/jamfile.jam b/src/boost/tools/build/test/rootless/test3/jamfile.jam new file mode 100644 index 00000000..ab8da6a0 --- /dev/null +++ b/src/boost/tools/build/test/rootless/test3/jamfile.jam @@ -0,0 +1,6 @@ +# Copyright 2018 Rene Rivera +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project root-foo : build-dir bins ; diff --git a/src/boost/tools/build/test/rootless/test3/sub/inner/a.cpp b/src/boost/tools/build/test/rootless/test3/sub/inner/a.cpp new file mode 100644 index 00000000..412a2bb4 --- /dev/null +++ b/src/boost/tools/build/test/rootless/test3/sub/inner/a.cpp @@ -0,0 +1,6 @@ +// Copyright 2018 Rene Rivera +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +int main() {} diff --git a/src/boost/tools/build/test/rootless/test3/sub/inner/jamfile.jam b/src/boost/tools/build/test/rootless/test3/sub/inner/jamfile.jam new file mode 100644 index 00000000..6aeddab3 --- /dev/null +++ b/src/boost/tools/build/test/rootless/test3/sub/inner/jamfile.jam @@ -0,0 +1,11 @@ +# Copyright 2018 Rene Rivera +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +actions foo +{ + echo "$(>)" > "$(<)" +} + +make a.txt : a.cpp : @foo ; diff --git a/src/boost/tools/build/test/scanner_causing_rebuilds.py b/src/boost/tools/build/test/scanner_causing_rebuilds.py new file mode 100755 index 00000000..d1ff66bf --- /dev/null +++ b/src/boost/tools/build/test/scanner_causing_rebuilds.py @@ -0,0 +1,132 @@ +#!/usr/bin/python + +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tests for a bug causing Boost Build's scanner targets to be rebuilt. +# unnecessarily in the following scenario: +# * We want to build target X requiring target A. +# * We have a multi-file action generating targets A & B. +# * Out action generates target B with a more recent timestamp than target A. +# * Target A includes target B. +# * Target A has a registered include scanner. +# Now even if our targets A & B have already been built and are up-to-date +# (e.g. in a state left by a previous successful build run), our scanner target +# tasked with scanning target A will be marked for updating, thus causing any +# targets depending on it to be updated/rebuilt as well. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("foo.jam", r""" +import common ; +import generators ; +import modules ; +import type ; +import types/cpp ; + +type.register FOO : foo ; +type.register BAR : bar ; +generators.register-standard foo.foo : FOO : CPP BAR ; + +local rule sleep-cmd ( delay ) +{ + if [ modules.peek : NT ] + { + return ping 127.0.0.1 -n $(delay) -w 1000 >NUL ; + } + else + { + return sleep $(delay) ; + } +} + +.touch = [ common.file-creation-command ] ; +.sleep = [ sleep-cmd 2 ] ; + +rule foo ( cpp bar : foo : properties * ) +{ + # We add the INCLUDE relationship between our generated CPP & BAR targets + # explicitly instead of relying on Boost Jam's internal implementation + # detail - automatically adding such relationships between all files + # generated by the same action. This way our test will continue to function + # correctly even if the related Boost Jam implementation detail changes. + # Note that adding this relationship by adding an #include directive in our + # generated CPP file is not good enough as such a relationship would get + # added only after the scanner target's relationships have already been + # established and they (as affected by our initial INCLUDE relationship) are + # the original reason for this test failing. + INCLUDES $(cpp) : $(bar) ; +} + +actions foo +{ + $(.touch) "$(<[1])" + $(.sleep) + $(.touch) "$(<[2])" +} +""") + +t.write( + 'foo.py', +""" +import os + +from b2.build import type as type_, generators +from b2.tools import common +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +type_.register('FOO', ['foo']) +type_.register('BAR', ['bar']) +generators.register_standard('foo.foo', ['FOO'], ['CPP', 'BAR']) + +def sleep_cmd(delay): + if os.name == 'nt': + return 'ping 127.0.0.1 -n {} -w 1000 >NUL'.format(delay) + return 'sleep {}'.format(delay) + +def foo(targets, sources, properties): + cpp, bar = targets + foo = sources[0] + # We add the INCLUDE relationship between our generated CPP & BAR targets + # explicitly instead of relying on Boost Jam's internal implementation + # detail - automatically adding such relationships between all files + # generated by the same action. This way our test will continue to function + # correctly even if the related Boost Jam implementation detail changes. + # Note that adding this relationship by adding an #include directive in our + # generated CPP file is not good enough as such a relationship would get + # added only after the scanner target's relationships have already been + # established and they (as affected by our initial INCLUDE relationship) are + # the original reason for this test failing. + bjam.call('INCLUDES', cpp, bar) + +ENGINE.register_action( + 'foo.foo', + ''' + {touch} "$(<[1])" + {sleep} + {touch} "$(<[2])" + '''.format(touch=common.file_creation_command(), sleep=sleep_cmd(2)) +) +""" +) + +t.write("x.foo", "") +t.write("jamroot.jam", """\ +import foo ; +lib x : x.foo : <link>static ; +""") + + +# Get everything built once. +t.run_build_system() + +# Simply rerunning the build without touching any of its source target files +# should not cause any files to be affected. +t.run_build_system() +t.expect_nothing_more() diff --git a/src/boost/tools/build/test/searched_lib.py b/src/boost/tools/build/test/searched_lib.py new file mode 100644 index 00000000..2081230a --- /dev/null +++ b/src/boost/tools/build/test/searched_lib.py @@ -0,0 +1,186 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2003, 2004, 2005, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test usage of searched-libs: one which are found via -l +# switch to the linker/compiler. + +import BoostBuild +import os +import string + +t = BoostBuild.Tester(use_test_config=False) + + +# To start with, we have to prepare a library to link with. +t.write("lib/jamroot.jam", "") +t.write("lib/jamfile.jam", "lib test_lib : test_lib.cpp ;") +t.write("lib/test_lib.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) +#endif +void foo() {} +"""); + +t.run_build_system(subdir="lib") +t.expect_addition("lib/bin/$toolset/debug*/test_lib.dll") + + +# Auto adjusting of suffixes does not work, since we need to +# change dll to lib. +if ( ( os.name == "nt" ) or os.uname()[0].lower().startswith("cygwin") ) and \ + ( BoostBuild.get_toolset() != "gcc" ): + t.copy("lib/bin/$toolset/debug*/test_lib.implib", "lib/test_lib.implib") + t.copy("lib/bin/$toolset/debug*/test_lib.dll", "lib/test_lib.dll") +else: + t.copy("lib/bin/$toolset/debug*/test_lib.dll", "lib/test_lib.dll") + + +# Test that the simplest usage of searched library works. +t.write("jamroot.jam", "") + +t.write("jamfile.jam", """\ +import path ; +import project ; +exe main : main.cpp helper ; +lib helper : helper.cpp test_lib ; +lib test_lib : : <name>test_lib <search>lib ; +""") + +t.write("main.cpp", """\ +void helper(); +int main() { helper(); } +""") + +t.write("helper.cpp", """\ +void foo(); +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +helper() { foo(); } +""") + +t.run_build_system(["-d2"]) +t.expect_addition("bin/$toolset/debug*/main.exe") +t.rm("bin/$toolset/debug/main.exe") +t.rm("bin/$toolset/debug/*/main.exe") + + +# Test that 'unit-test' will correctly add runtime paths to searched libraries. +t.write("jamfile.jam", """\ +import path ; +import project ; +import testing ; + +project : requirements <hardcode-dll-paths>false ; + +unit-test main : main.cpp helper ; +lib helper : helper.cpp test_lib ; +lib test_lib : : <name>test_lib <search>lib ; +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/main.passed") +t.rm("bin/$toolset/debug/main.exe") +t.rm("bin/$toolset/debug/*/main.exe") + + +# Now try using searched lib from static lib. Request shared version of searched +# lib, since we do not have a static one handy. +t.write("jamfile.jam", """\ +exe main : main.cpp helper ; +lib helper : helper.cpp test_lib/<link>shared : <link>static ; +lib test_lib : : <name>test_lib <search>lib ; +""") + +t.run_build_system(stderr=None) +t.expect_addition("bin/$toolset/debug*/main.exe") +t.expect_addition("bin/$toolset/debug/link-static*/helper.lib") +t.rm("bin/$toolset/debug/main.exe") +t.rm("bin/$toolset/debug/*/main.exe") + +# A regression test: <library>property referring to searched-lib was being +# mishandled. As the result, we were putting target name to the command line! +# Note that +# g++ ...... <.>z +# works nicely in some cases, sending output from compiler to file 'z'. This +# problem shows up when searched libs are in usage requirements. +t.write("jamfile.jam", "exe main : main.cpp d/d2//a ;") +t.write("main.cpp", """\ +void foo(); +int main() { foo(); } +""") + +t.write("d/d2/jamfile.jam", """\ +lib test_lib : : <name>test_lib <search>../../lib ; +lib a : a.cpp : : : <library>test_lib ; +""") + +t.write("d/d2/a.cpp", """\ +#ifdef _WIN32 +__declspec(dllexport) int force_library_creation_for_a; +#endif +""") + +t.run_build_system() + + +# A regression test. Searched targets were not associated with any properties. +# For that reason, if the same searched lib is generated with two different +# properties, we had an error saying they are actualized to the same Jam target +# name. +t.write("jamroot.jam", "") + +t.write("a.cpp", "") + +# The 'l' library will be built in two variants: 'debug' (directly requested) +# and 'release' (requested from 'a'). +t.write("jamfile.jam", """\ +exe a : a.cpp l/<variant>release ; +lib l : : <name>l_d <variant>debug ; +lib l : : <name>l_r <variant>release ; +""") + +t.run_build_system(["-n"]) + + +# A regression test. Two virtual target with the same properties were created +# for 'l' target, which caused and error to be reported when actualizing +# targets. The final error is correct, but we should not create two duplicated +# targets. Thanks to Andre Hentz for finding this bug. +t.write("jamroot.jam", "") +t.write("a.cpp", "") +t.write("jamfile.jam", """\ +project a : requirements <runtime-link>static ; +static-lib a : a.cpp l ; +lib l : : <name>l_f ; +""") + +t.run_build_system(["-n"]) + + +# Make sure plain "lib foobar ; " works. +t.write("jamfile.jam", """\ +exe a : a.cpp foobar ; +lib foobar ; +""") + +t.run_build_system(["-n", "-d2"]) +t.fail_test(t.stdout().find("foobar") == -1) + + +# Make sure plain "lib foo bar ; " works. +t.write("jamfile.jam", """\ +exe a : a.cpp foo bar ; +lib foo bar ; +""") + +t.run_build_system(["-n", "-d2"]) +t.fail_test(t.stdout().find("foo") == -1) +t.fail_test(t.stdout().find("bar") == -1) + +t.cleanup() diff --git a/src/boost/tools/build/test/skipping.py b/src/boost/tools/build/test/skipping.py new file mode 100644 index 00000000..a187a4be --- /dev/null +++ b/src/boost/tools/build/test/skipping.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that V2 does not fail gracelessy when any target is skipped. + +import BoostBuild + +# Create a temporary working directory. +t = BoostBuild.Tester(use_test_config=False) + +t.write("a.cpp", "int main() {}\n") +t.write("b.cpp", "int main() {}\n") +t.write("c.cpp", "int main() {}\n") +t.write("jamroot.jam", """\ +import feature ; +feature.feature foo : 1 2 : link-incompatible ; +exe a : a.cpp : <foo>1 ; +exe b : b.cpp : <foo>2 ; +exe c : c.cpp ; +""") + +t.run_build_system(["foo=1"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/sort_rule.py b/src/boost/tools/build/test/sort_rule.py new file mode 100755 index 00000000..39537326 --- /dev/null +++ b/src/boost/tools/build/test/sort_rule.py @@ -0,0 +1,98 @@ +#!/usr/bin/python + +# Copyright (C) 2008. Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests for the Boost Jam builtin SORT rule. + +from __future__ import print_function + +import BoostBuild + + +############################################################################### +# +# testSORTCorrectness() +# --------------------- +# +############################################################################### + +def testSORTCorrectness(): + """Testing that Boost Jam's SORT builtin rule actually sorts correctly.""" + t = BoostBuild.Tester(["-ftest.jam", "-d1"], pass_toolset=False, + use_test_config=False) + + t.write("test.jam", """\ +NOCARE all ; +source-data = 1 8 9 2 7 3 4 7 1 27 27 9 98 98 1 1 4 5 6 2 3 4 8 1 -2 -2 0 0 0 ; +target-data = -2 -2 0 0 0 1 1 1 1 1 2 2 27 27 3 3 4 4 4 5 6 7 7 8 8 9 9 98 98 ; +ECHO "starting up" ; +sorted-data = [ SORT $(source-data) ] ; +ECHO "done" ; +if $(sorted-data) != $(target-data) +{ + ECHO "Source :" $(source-data) ; + ECHO "Expected :" $(target-data) ; + ECHO "SORT returned:" $(sorted-data) ; + EXIT "SORT error" : -2 ; +} +""") + + t.run_build_system() + t.expect_output_lines("starting up") + t.expect_output_lines("done") + t.expect_output_lines("SORT error", False) + + t.cleanup() + + +############################################################################### +# +# testSORTDuration() +# ------------------ +# +############################################################################### + +def testSORTDuration(): + """ + Regression test making sure Boost Jam's SORT builtin rule does not get + quadratic behaviour again in this use case. + + """ + t = BoostBuild.Tester(["-ftest.jam", "-d1"], pass_toolset=False, + use_test_config=False) + + f = open(t.workpath("test.jam"), "w") + print("data = ", file=f) + for i in range(0, 20000): + if i % 2: + print('"aaa"', file=f) + else: + print('"bbb"', file=f) + print("""; + +ECHO "starting up" ; +sorted = [ SORT $(data) ] ; +ECHO "done" ; +NOCARE all ; +""", file=f) + f.close() + + t.run_build_system(expected_duration=1) + t.expect_output_lines("starting up") + t.expect_output_lines("done") + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +testSORTCorrectness() +testSORTDuration() diff --git a/src/boost/tools/build/test/source_locations.py b/src/boost/tools/build/test/source_locations.py new file mode 100644 index 00000000..8123a186 --- /dev/null +++ b/src/boost/tools/build/test/source_locations.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +# Copyright (C) Craig Rodrigues 2005. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that projects with multiple source-location directories are handled OK. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", """ +path-constant SRC1 : "./src1" ; +path-constant SRC2 : "./src2" ; +path-constant SRC3 : "./src3" ; +path-constant BUILD : "build" ; + +project : requirements <include>$(SRC1)/include <threading>multi + : build-dir $(BUILD) ; + +build-project project1 ; +""") + +t.write("project1/jamfile.jam", """ +project project1 : source-location $(SRC1) $(SRC2) $(SRC3) ; +SRCS = s1.cpp s2.cpp testfoo.cpp ; +exe test : $(SRCS) ; +""") + +t.write("src1/s1.cpp", "int main() {}\n") +t.write("src2/s2.cpp", "void hello() {}\n") +t.write("src3/testfoo.cpp", "void testfoo() {}\n") + +# This file should not be picked up, because "src2" is before "src3" in the list +# of source directories. +t.write("src3/s2.cpp", "void hello() {}\n") + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/source_order.py b/src/boost/tools/build/test/source_order.py new file mode 100755 index 00000000..f21710a8 --- /dev/null +++ b/src/boost/tools/build/test/source_order.py @@ -0,0 +1,84 @@ +#!/usr/bin/python + +# Copyright 2013 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tests that action sources are not reordered + +import BoostBuild + +t = BoostBuild.Tester() + +t.write("check-order.jam", """\ +import type ; +import generators ; + +type.register ORDER_TEST : order-test ; + +SPACE = " " ; +nl = "\n" ; +actions check-order +{ + echo$(SPACE)$(>[1])>$(<[1]) + echo$(SPACE)$(>[2-])>>$(<[1])$(nl) +} + +generators.register-composing check-order.check-order : C : ORDER_TEST ; +""") + +t.write( + 'check-order.py', +""" +import bjam + +from b2.build import type as type_, generators +from b2.tools import common +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +type_.register('ORDER_TEST', ['order-test']) + +generators.register_composing('check-order.check-order', ['C'], ['ORDER_TEST']) + +def check_order(targets, sources, properties): + ENGINE.set_target_variable(targets, 'SPACE', ' ') + ENGINE.set_target_variable(targets, 'nl', '\\n') + +ENGINE.register_action( + 'check-order.check-order', + function=check_order, + command=''' + echo$(SPACE)$(>[1])>$(<[1]) + echo$(SPACE)$(>[2-])>>$(<[1])$(nl) + ''' +) +""" +) + +# The aliases are necessary for this test, since +# the targets were sorted by virtual target +# id, not by file name. +t.write("jamroot.jam", """\ +import check-order ; +alias file1 : file1.c ; +alias file2 : file2.c ; +alias file3 : file3.c ; +order-test check : file2 file1 file3 ; +""") + +t.write("file1.c", "") +t.write("file2.c", "") +t.write("file3.c", "") + +t.run_build_system() +t.expect_addition("bin/check.order-test") +t.expect_content("bin/check.order-test", """\ +file2.c +file1.c +file3.c +""", True) + +t.cleanup() diff --git a/src/boost/tools/build/test/space_in_path.py b/src/boost/tools/build/test/space_in_path.py new file mode 100755 index 00000000..7f0c041a --- /dev/null +++ b/src/boost/tools/build/test/space_in_path.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright 2012 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that paths containing spaces are handled correctly by actions. + +import BoostBuild +import os + +t = BoostBuild.Tester(use_test_config=False) + +t.write("has space/jamroot.jam", """\ +import testing ; +unit-test test : test.cpp ; +actions write-file +{ + @(STDOUT:E=okay) >"$(<)" +} +make test.txt : : @write-file ; +""") +t.write("has space/test.cpp", "int main() {}\n") + +tmpdir = t.workpath("has space") +try: + oldtmp = os.environ["TMP"] +except: + oldtmp = None +try: + oldtmpdir = os.environ["TMPDIR"] +except: + oldtmpdir = None +os.environ["TMP"] = tmpdir; # Windows +os.environ["TMPDIR"] = tmpdir; # *nix + +try: + t.run_build_system(["has space"]) + t.expect_addition("has space/bin/test.txt") + t.expect_addition("has space/bin/$toolset/debug*/test.passed") +finally: + if oldtmp is not None: + os.environ["TMP"] = oldtmp + else: + del os.environ["TMP"] + if oldtmpdir is not None: + os.environ["TMPDIR"] = oldtmpdir + else: + del os.environ["TMPDIR"] + +t.cleanup() diff --git a/src/boost/tools/build/test/stage.py b/src/boost/tools/build/test/stage.py new file mode 100644 index 00000000..4dd4e2f9 --- /dev/null +++ b/src/boost/tools/build/test/stage.py @@ -0,0 +1,207 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test staging. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "") +t.write("jamfile.jam", """\ +lib a : a.cpp ; +stage dist : a a.h auxilliary/1 ; +""") +t.write("a.cpp", """\ +int +#ifdef _WIN32 +__declspec(dllexport) +#endif +must_export_something; +""") +t.write("a.h", "") +t.write("auxilliary/1", "") + +t.run_build_system() +t.expect_addition(["dist/a.dll", "dist/a.h", "dist/1"]) + + +# Regression test: the following was causing a "duplicate target name" error. +t.write("jamfile.jam", """\ +project : requirements <hardcode-dll-paths>true ; +lib a : a.cpp ; +stage dist : a a.h auxilliary/1 ; +alias dist-alias : dist ; +""") + +t.run_build_system() + + +# Test the <location> property. +t.write("jamfile.jam", """\ +lib a : a.cpp ; +stage dist : a : <variant>debug:<location>ds <variant>release:<location>rs ; +""") + +t.run_build_system() +t.expect_addition("ds/a.dll") + +t.run_build_system(["release"]) +t.expect_addition("rs/a.dll") + + +# Test the <location> property in subprojects. Thanks to Kirill Lapshin for the +# bug report. + +t.write("jamroot.jam", "path-constant DIST : dist ;") +t.write("jamfile.jam", "build-project d ;") +t.write("d/jamfile.jam", """\ +exe a : a.cpp ; +stage dist : a : <location>$(DIST) ; +""") +t.write("d/a.cpp", "int main() {}\n") + +t.run_build_system() +t.expect_addition("dist/a.exe") + +t.rm("dist") + +# Workaround a BIG BUG: the response file is not deleted, even if application +# *is* deleted. We will try to use the same response file when building from +# subdir, with very bad results. +t.rm("d/bin") +t.run_build_system(subdir="d") +t.expect_addition("dist/a.exe") + + +# Check that 'stage' does not incorrectly reset target suffixes. +t.write("a.cpp", "int main() {}\n") +t.write("jamroot.jam", """\ +import type ; +type.register MYEXE : : EXE ; +type.set-generated-target-suffix MYEXE : <optimization>off : myexe ; +""") + +# Since <optimization>off is in properties when 'a' is built and staged, its +# suffix should be "myexe". +t.write("jamfile.jam", """\ +stage dist : a ; +myexe a : a.cpp ; +""") + +t.run_build_system() +t.expect_addition("dist/a.myexe") + +# Test 'stage's ability to traverse dependencies. +t.write("a.cpp", "int main() {}\n") +t.write("l.cpp", """\ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +foo() {} +""") +t.write("jamfile.jam", """\ +lib l : l.cpp ; +exe a : a.cpp l ; +stage dist : a : <install-dependencies>on <install-type>EXE <install-type>LIB ; +""") +t.write("jamroot.jam", "") +t.rm("dist") + +t.run_build_system() +t.expect_addition("dist/a.exe") +t.expect_addition("dist/l.dll") + +# Check that <use> properties are ignored the traversing target for staging. +t.copy("l.cpp", "l2.cpp") +t.copy("l.cpp", "l3.cpp") +t.write("jamfile.jam", """\ +lib l2 : l2.cpp ; +lib l3 : l3.cpp ; +lib l : l.cpp : <use>l2 <dependency>l3 ; +exe a : a.cpp l ; +stage dist : a : <install-dependencies>on <install-type>EXE <install-type>LIB ; +""") +t.rm("dist") + +t.run_build_system() +t.expect_addition("dist/l3.dll") +t.expect_nothing("dist/l2.dll") + +# Check if <dependency> on 'stage' works. +t.rm(".") +t.write("jamroot.jam", """\ +stage a1 : a1.txt : <location>dist ; +stage a2 : a2.txt : <location>dist <dependency>a1 ; +""") +t.write("a1.txt", "") +t.write("a2.txt", "") +t.run_build_system(["a2"]) +t.expect_addition(["dist/a1.txt", "dist/a2.txt"]) + +# Regression test: check that <location>. works. +t.rm(".") +t.write("jamroot.jam", "stage a1 : d/a1.txt : <location>. ;") +t.write("d/a1.txt", "") + +t.run_build_system() +t.expect_addition("a1.txt") + +# Test that relative paths of sources can be preserved. +t.rm(".") +t.write("jamroot.jam", "install dist : a/b/c.h : <install-source-root>. ;") +t.write("a/b/c.h", "") + +t.run_build_system() +t.expect_addition("dist/a/b/c.h") + +t.write("jamroot.jam", "install dist : a/b/c.h : <install-source-root>a ;") +t.write("a/b/c.h", "") + +t.run_build_system() +t.expect_addition("dist/b/c.h") + +t.rm(".") +t.write("build/jamroot.jam", """\ +install dist : ../a/b/c.h : <location>../dist <install-source-root>../a ; +""") +t.write("a/b/c.h", "") + +t.run_build_system(subdir="build") +t.expect_addition("dist/b/c.h") + +t.write("jamroot.jam", "install dist2 : a/b/c.h : <install-source-root>a ;") +t.write("a/b/c.h", "") +t.write("sub/jamfile.jam", "alias h : ..//dist2 ;") + +t.run_build_system(subdir="sub") +t.expect_addition("dist2/b/c.h") + +# Test that when installing .cpp files, we do not scan include dependencies. +t.rm(".") +t.write("jamroot.jam", "install dist : a.cpp ;") +t.write("a.cpp", '#include "a.h"') +t.write("a.h", "") + +t.run_build_system() +t.expect_addition("dist/a.cpp") + +t.touch("a.h") + +t.run_build_system() +t.expect_nothing("dist/a.cpp") + +# Test that <name> property works, when there is just one file in sources. +t.rm(".") +t.write("jamroot.jam", "install dist : a.cpp : <name>b.cpp ;") +t.write("a.cpp", "test file") + +t.run_build_system() +t.expect_addition("dist/b.cpp") + +t.cleanup() diff --git a/src/boost/tools/build/test/standalone.py b/src/boost/tools/build/test/standalone.py new file mode 100644 index 00000000..6d9e9e86 --- /dev/null +++ b/src/boost/tools/build/test/standalone.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + + +# Regression tests: standalone project were not able to refer to targets +# declared in themselves. + +t.write("a.cpp", "int main() {}\n") +t.write("jamroot.jam", "import standalone ;") +t.write("standalone.jam", """\ +import alias ; +import project ; + +project.initialize $(__name__) ; +project standalone ; + +local pwd = [ PWD ] ; + +alias x : $(pwd)/../a.cpp ; +alias runtime : x ; +""") + +t.write("standalone.py", """\ +from b2.manager import get_manager + +# FIXME: this is ugly as death +get_manager().projects().initialize(__name__) + +import os ; + +# This use of list as parameter is also ugly. +project(['standalone']) + +pwd = os.getcwd() +alias('x', [os.path.join(pwd, '../a.cpp')]) +alias('runtime', ['x']) +""") + + +t.write("sub/jamfile.jam", "stage bin : /standalone//runtime ;") + +t.run_build_system(subdir="sub") +t.expect_addition("sub/bin/a.cpp") + +t.cleanup() diff --git a/src/boost/tools/build/test/startup/boost-root/boost-build.jam b/src/boost/tools/build/test/startup/boost-root/boost-build.jam new file mode 100644 index 00000000..098889f7 --- /dev/null +++ b/src/boost/tools/build/test/startup/boost-root/boost-build.jam @@ -0,0 +1,7 @@ +# Copyright 2002 Dave Abrahams +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Emulate v1 behavior; with the boost-build file in the boost root directory. +boost-build build ; diff --git a/src/boost/tools/build/test/startup/boost-root/build/boost-build.jam b/src/boost/tools/build/test/startup/boost-root/build/boost-build.jam new file mode 100644 index 00000000..610ec79e --- /dev/null +++ b/src/boost/tools/build/test/startup/boost-root/build/boost-build.jam @@ -0,0 +1,6 @@ +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# The presence of this file emulates the Boost 1.27.0 release +include $(BOOST_ROOT)/tools/build/bootstrap.jam ; diff --git a/src/boost/tools/build/test/startup/boost-root/build/bootstrap.jam b/src/boost/tools/build/test/startup/boost-root/build/bootstrap.jam new file mode 100644 index 00000000..2ee3507c --- /dev/null +++ b/src/boost/tools/build/test/startup/boost-root/build/bootstrap.jam @@ -0,0 +1,7 @@ +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +ECHO build system bootstrapped ; +DEPENDS all : nothing ; +NOTFILE nothing ; diff --git a/src/boost/tools/build/test/startup/bootstrap-env/boost-build.jam b/src/boost/tools/build/test/startup/bootstrap-env/boost-build.jam new file mode 100644 index 00000000..67a285e7 --- /dev/null +++ b/src/boost/tools/build/test/startup/bootstrap-env/boost-build.jam @@ -0,0 +1,5 @@ +# Copyright 2002 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +boost-build ; diff --git a/src/boost/tools/build/test/startup/bootstrap-explicit/boost-build.jam b/src/boost/tools/build/test/startup/bootstrap-explicit/boost-build.jam new file mode 100644 index 00000000..27d9108b --- /dev/null +++ b/src/boost/tools/build/test/startup/bootstrap-explicit/boost-build.jam @@ -0,0 +1,6 @@ +# Copyright 2002 Dave Abrahams +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +boost-build ../boost-root/build ; diff --git a/src/boost/tools/build/test/startup/bootstrap-implicit/readme.txt b/src/boost/tools/build/test/startup/bootstrap-implicit/readme.txt new file mode 100644 index 00000000..0278716e --- /dev/null +++ b/src/boost/tools/build/test/startup/bootstrap-implicit/readme.txt @@ -0,0 +1,5 @@ +Copyright 2002 Dave Abrahams +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +This file is only here so that cvs update -P won't fail to create a directory diff --git a/src/boost/tools/build/test/startup/no-bootstrap1/boost-build.jam b/src/boost/tools/build/test/startup/no-bootstrap1/boost-build.jam new file mode 100644 index 00000000..b1b4dc69 --- /dev/null +++ b/src/boost/tools/build/test/startup/no-bootstrap1/boost-build.jam @@ -0,0 +1,6 @@ +# Copyright 2002 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Bootstrap file not found via implicit lookup in BOOST_BUILD_PATH +boost-build ; diff --git a/src/boost/tools/build/test/startup/no-bootstrap1/subdir/readme.txt b/src/boost/tools/build/test/startup/no-bootstrap1/subdir/readme.txt new file mode 100644 index 00000000..00f428d4 --- /dev/null +++ b/src/boost/tools/build/test/startup/no-bootstrap1/subdir/readme.txt @@ -0,0 +1,5 @@ +Copyright 2002 Dave Abrahams +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +This file is only here so cvs update -P will create the directory. diff --git a/src/boost/tools/build/test/startup/no-bootstrap2/boost-build.jam b/src/boost/tools/build/test/startup/no-bootstrap2/boost-build.jam new file mode 100644 index 00000000..505dcd77 --- /dev/null +++ b/src/boost/tools/build/test/startup/no-bootstrap2/boost-build.jam @@ -0,0 +1,6 @@ +# Copyright 2002 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Bootstrap file not found via explicit lookup in . +boost-build . ; diff --git a/src/boost/tools/build/test/startup/no-bootstrap3/boost-build.jam b/src/boost/tools/build/test/startup/no-bootstrap3/boost-build.jam new file mode 100644 index 00000000..252a3993 --- /dev/null +++ b/src/boost/tools/build/test/startup/no-bootstrap3/boost-build.jam @@ -0,0 +1,5 @@ +# Copyright 2002 Dave Abrahams +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Call to boost-build is intentionally missing diff --git a/src/boost/tools/build/test/startup_v2.py b/src/boost/tools/build/test/startup_v2.py new file mode 100644 index 00000000..2dd867a1 --- /dev/null +++ b/src/boost/tools/build/test/startup_v2.py @@ -0,0 +1,94 @@ +#!/usr/bin/python + +# Copyright 2002 Dave Abrahams +# Copyright 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os.path +import re + + +def check_for_existing_boost_build_jam(t): + """ + This test depends on no boost-build.jam file existing in any of the + folders along the current folder's path. If it does exist, not only would + this test fail but it could point to a completely wrong Boost Build + installation, thus causing headaches when attempting to diagnose the + problem. That is why we explicitly check for this scenario. + + """ + problem = find_up_to_root(t.workdir, "boost-build.jam") + if problem: + BoostBuild.annotation("misconfiguration", """\ +This test expects to be run from a folder with no 'boost-build.jam' file in any +of the folders along its path. + +Working folder: + '%s' + +Problematic boost-build.jam found at: + '%s' + +Please remove this file or change the test's working folder and rerun the test. +""" % (t.workdir, problem)) + t.fail_test(1, dump_stdio=False, dump_stack=False) + + +def find_up_to_root(folder, name): + last = "" + while last != folder: + candidate = os.path.join(folder, name) + if os.path.exists(candidate): + return candidate + last = folder + folder = os.path.dirname(folder) + + +def match_re(actual, expected): + return re.match(expected, actual, re.DOTALL) != None + + +t = BoostBuild.Tester(match=match_re, boost_build_path="", pass_toolset=0) +t.set_tree("startup") +check_for_existing_boost_build_jam(t) + +t.run_build_system(status=1, stdout= +r"""Unable to load Boost\.Build: could not find "boost-build\.jam" +.*Attempted search from .* up to the root""") + +t.run_build_system(status=1, subdir="no-bootstrap1", + stdout=r"Unable to load Boost\.Build: could not find build system\." + r".*attempted to load the build system by invoking" + r".*'boost-build ;'" + r'.*but we were unable to find "bootstrap\.jam"') + +# Descend to a subdirectory which /does not/ contain a boost-build.jam file, +# and try again to test the crawl-up behavior. +t.run_build_system(status=1, subdir=os.path.join("no-bootstrap1", "subdir"), + stdout=r"Unable to load Boost\.Build: could not find build system\." + r".*attempted to load the build system by invoking" + r".*'boost-build ;'" + r'.*but we were unable to find "bootstrap\.jam"') + +t.run_build_system(status=1, subdir="no-bootstrap2", + stdout=r"Unable to load Boost\.Build: could not find build system\." + r".*attempted to load the build system by invoking" + r".*'boost-build \. ;'" + r'.*but we were unable to find "bootstrap\.jam"') + +t.run_build_system(status=1, subdir='no-bootstrap3', stdout= +r"""Unable to load Boost.Build +.*boost-build\.jam" was found.* +However, it failed to call the "boost-build" rule""") + +# Test bootstrapping based on BOOST_BUILD_PATH. +t.run_build_system(["-sBOOST_BUILD_PATH=../boost-root/build"], + subdir="bootstrap-env", stdout="build system bootstrapped") + +# Test bootstrapping based on an explicit path in boost-build.jam. +t.run_build_system(subdir="bootstrap-explicit", + stdout="build system bootstrapped") + +t.cleanup() diff --git a/src/boost/tools/build/test/static_and_shared_library.py b/src/boost/tools/build/test/static_and_shared_library.py new file mode 100755 index 00000000..c3443e92 --- /dev/null +++ b/src/boost/tools/build/test/static_and_shared_library.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Dave Abrahams +# Copyright 2002, 2003, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) +t.write("jamroot.jam", "") +t.write("lib/c.cpp", "int bar() { return 0; }\n") +t.write("lib/jamfile.jam", """\ +static-lib auxilliary1 : c.cpp ; +lib auxilliary2 : c.cpp ; +""") + +def reset(): + t.rm("lib/bin") + +t.run_build_system(subdir='lib') +t.expect_addition("lib/bin/$toolset/debug*/" * BoostBuild.List("c.obj " + "auxilliary1.lib auxilliary2.dll")) + +reset() +t.run_build_system(["link=shared"], subdir="lib") +t.expect_addition("lib/bin/$toolset/debug*/" * BoostBuild.List("c.obj " + "auxilliary1.lib auxilliary2.dll")) + +reset() +t.run_build_system(["link=static"], subdir="lib") +t.expect_addition("lib/bin/$toolset/debug*/" * BoostBuild.List( + "c.obj auxilliary1.lib auxilliary2.lib")) +t.expect_nothing_more() + +t.cleanup() diff --git a/src/boost/tools/build/test/suffix.py b/src/boost/tools/build/test/suffix.py new file mode 100644 index 00000000..b31dd173 --- /dev/null +++ b/src/boost/tools/build/test/suffix.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +# Copyright 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester() + +# Regression test: when staging V2 used to change suffixes on targets +# corresponding to real files. +t.write("jamfile.jam", """ +import type : register ; +register A : a1 a2 a3 ; +stage a : a.a3 ; +""") + +t.write("jamroot.jam", "") +t.write("a.a3", "") + +t.run_build_system() +t.expect_addition("a/a.a3"); + +# Regression test: we should be able to specify empty suffix for derived target +# type, even if base type has non-empty suffix. +t.write("a.cpp", "") + +t.write("suffixes.jam", """ +import type ; +import generators ; +import common ; + +type.register First : first : ; +type.register Second : "" : First ; + +generators.register-standard $(__name__).second : CPP : Second ; + +rule second +{ + TOUCH on $(<) = [ common.file-creation-command ] ; +} + +actions second +{ + $(TOUCH) $(<) +} +""") + +t.write("suffixes.py", """ +import b2.build.type as type +import b2.build.generators as generators +import b2.tools.common as common + +from b2.manager import get_manager + +type.register("First", ["first"]) +type.register("Second", [""], "First") + +generators.register_standard("suffixes.second", ["CPP"], ["Second"]) + +get_manager().engine().register_action("suffixes.second", + "%s $(<)" % common.file_creation_command()) + +""") + +t.write("jamroot.jam", """ +import suffixes ; +""") + +t.write("jamfile.jam", """ +second a : a.cpp ; +""") + +t.run_build_system() +t.expect_addition("bin/a") + +t.cleanup() diff --git a/src/boost/tools/build/test/symlink.py b/src/boost/tools/build/test/symlink.py new file mode 100644 index 00000000..ab02db2f --- /dev/null +++ b/src/boost/tools/build/test/symlink.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the 'symlink' rule. + +from __future__ import print_function + +import os +import BoostBuild + + +if os.name != 'posix': + print("The symlink tests can be run on posix only.") + import sys + sys.exit(1) + + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "import gcc ;") + +t.write("jamfile.jam", """ +exe hello : hello.cpp ; +symlink hello_release : hello/<variant>release ; +symlink hello_debug : hello/<variant>debug ; +symlink links/hello_release : hello/<variant>release ; +""") + +t.write("hello.cpp", """ +int main() {} +""") + +t.run_build_system() +t.expect_addition([ + 'hello_debug.exe', + 'hello_release.exe', + 'links/hello_release.exe']) + +t.cleanup() diff --git a/src/boost/tools/build/test/tag.py b/src/boost/tools/build/test/tag.py new file mode 100644 index 00000000..adf2fce6 --- /dev/null +++ b/src/boost/tools/build/test/tag.py @@ -0,0 +1,122 @@ +#!/usr/bin/python + +# Copyright (C) 2003. Pedro Ferreira +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + + +############################################################################### +# +# test_folder_with_dot_in_name() +# ------------------------------ +# +############################################################################### + +def test_folder_with_dot_in_name(t): + """ + Regression test: the 'tag' feature did not work in directories that had a + dot in their name. + + """ + t.write("version-1.32.0/jamroot.jam", """\ +project test : requirements <tag>@$(__name__).tag ; + +rule tag ( name : type ? : property-set ) +{ + # Do nothing, just make sure the rule is invoked OK. + ECHO The tag rule has been invoked. ; +} +exe a : a.cpp ; +""") + t.write("version-1.32.0/a.cpp", "int main() {}\n") + + t.run_build_system(subdir="version-1.32.0") + t.expect_addition("version-1.32.0/bin/$toolset/debug*/a.exe") + t.expect_output_lines("The tag rule has been invoked.") + + +############################################################################### +# +# test_tag_property() +# ------------------- +# +############################################################################### + +def test_tag_property(t): + """Basic tag property test.""" + + t.write("jamroot.jam", """\ +import virtual-target ; + +rule tag ( name : type ? : property-set ) +{ + local tags ; + switch [ $(property-set).get <variant> ] + { + case debug : tags += d ; + case release : tags += r ; + } + switch [ $(property-set).get <link> ] + { + case shared : tags += s ; + case static : tags += t ; + } + if $(tags) + { + return [ virtual-target.add-prefix-and-suffix $(name)_$(tags:J="") + : $(type) : $(property-set) ] ; + } +} + +# Test both fully-qualified and local name of the rule +exe a : a.cpp : <tag>@$(__name__).tag ; +lib b : a.cpp : <tag>@tag ; +stage c : a ; +""") + + t.write("a.cpp", """\ +int main() {} +#ifdef _MSC_VER +__declspec (dllexport) void x () {} +#endif +""") + + file_list = ( + BoostBuild.List("bin/$toolset/debug*/a_ds.exe") + + BoostBuild.List("bin/$toolset/debug*/b_ds.dll") + + BoostBuild.List("c/a_ds.exe") + + BoostBuild.List("bin/$toolset/release*/a_rs.exe") + + BoostBuild.List("bin/$toolset/release*/b_rs.dll") + + BoostBuild.List("c/a_rs.exe") + + BoostBuild.List("bin/$toolset/debug*/a_dt.exe") + + BoostBuild.List("bin/$toolset/debug*/b_dt.lib") + + BoostBuild.List("c/a_dt.exe") + + BoostBuild.List("bin/$toolset/release*/a_rt.exe") + + BoostBuild.List("bin/$toolset/release*/b_rt.lib") + + BoostBuild.List("c/a_rt.exe")) + + variants = ["debug", "release", "link=static,shared"] + + t.run_build_system(variants) + t.expect_addition(file_list) + + t.run_build_system(variants + ["clean"]) + t.expect_removal(file_list) + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +t = BoostBuild.Tester(use_test_config=False) + +test_tag_property(t) +test_folder_with_dot_in_name(t) + +t.cleanup() diff --git a/src/boost/tools/build/test/template.py b/src/boost/tools/build/test/template.py new file mode 100644 index 00000000..f67e7398 --- /dev/null +++ b/src/boost/tools/build/test/template.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +# Copyright (C) FILL SOMETHING HERE 2006. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# This file is template for Boost.Build tests. It creates a simple project that +# builds one exe from one source, and checks that the exe is really created. + +import BoostBuild + + +# Create a temporary working directory. +t = BoostBuild.Tester() + +# Create the needed files. +t.write("jamroot.jam", """ +exe hello : hello.cpp ; +""") + +t.write("hello.cpp", """ +int main() {} +""" + +# Run the build. +t.run_build_system() + +# First, create a list of three pathnames. +file_list = BoostBuild.List("bin/$toolset/debug*/") * \ + BoostBuild.List("hello.exe hello.obj") +# Second, assert that those files were added as result of the last build system +# invocation. +t.expect_addition(file_list) + +# Invoke the build system once again. +t.run_build_system("clean") +# Check if the files added previously were removed. +t.expect_removal(file_list) + +# Remove temporary directories. +t.cleanup() diff --git a/src/boost/tools/build/test/test-config-example.jam b/src/boost/tools/build/test/test-config-example.jam new file mode 100644 index 00000000..6cb813fa --- /dev/null +++ b/src/boost/tools/build/test/test-config-example.jam @@ -0,0 +1,19 @@ +# Copyright 2004, 2005, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +# Skeleton for test configuration. If your local configuration +# interferes with testing, rename this files to 'test-system.jam' +# and tweak it. When tests are run, only this file will be loaded, +# while site-config.jam and user-config.jam will be ignored. + +using gcc ; + +using boostbook + : /home/ghost/Store/docbook/xsl + : /home/ghost/Store/docbook/dtd + : /home/ghost/Work/Boost/boost-svn/tools/boostbook + ; +using doxygen ; +using qt4 : /usr/share/qt4 ; diff --git a/src/boost/tools/build/test/test.jam b/src/boost/tools/build/test/test.jam new file mode 100644 index 00000000..1ae1a205 --- /dev/null +++ b/src/boost/tools/build/test/test.jam @@ -0,0 +1,39 @@ +# Copyright 2001, 2002, 2003 Dave Abrahams +# Copyright 2002 Rene Rivera +# Copyright 2002, 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# util +import assert ; +import container ; +import indirect ; +import numbers ; +import order ; +import os ; +import path ; +import print ; +import regex ; +import sequence ; +import set ; +import string ; +import utility ; + +# kernel +import "class" ; +import errors ; +import modules ; + +# build +import build-request ; +import feature ; +import property ; +import toolset ; +import type ; +import version ; + +# tools +import common ; + +actions nothing { } +nothing all ; diff --git a/src/boost/tools/build/test/test1.py b/src/boost/tools/build/test/test1.py new file mode 100644 index 00000000..79d14222 --- /dev/null +++ b/src/boost/tools/build/test/test1.py @@ -0,0 +1,18 @@ +#!/usr/bin/python + +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) + +t.write("test.jam", """ +actions unbuilt { } +unbuilt all ; +ECHO "Hi" ; +""") + +t.run_build_system("-ftest.jam", stdout="Hi\n") +t.cleanup() diff --git a/src/boost/tools/build/test/test2.py b/src/boost/tools/build/test/test2.py new file mode 100644 index 00000000..b7c99be1 --- /dev/null +++ b/src/boost/tools/build/test/test2.py @@ -0,0 +1,25 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Dave Abrahams +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester() + +t.set_tree("test2") + +file_list = 'bin/$toolset/debug*/' * \ + BoostBuild.List("foo foo.o") + +t.run_build_system("-sBOOST_BUILD_PATH=" + t.original_workdir + "/..") +t.expect_addition(file_list) + + +t.write("foo.cpp", "int main() {}\n") +t.run_build_system("-d2 -sBOOST_BUILD_PATH=" + t.original_workdir + "/..") +t.expect_touch(file_list) + +t.cleanup() diff --git a/src/boost/tools/build/test/test2/foo.cpp b/src/boost/tools/build/test/test2/foo.cpp new file mode 100644 index 00000000..135fa90f --- /dev/null +++ b/src/boost/tools/build/test/test2/foo.cpp @@ -0,0 +1,10 @@ +// Copyright (c) 2003 Vladimir Prus +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org +// + +int main() { return 0; } diff --git a/src/boost/tools/build/test/test2/jamroot.jam b/src/boost/tools/build/test/test2/jamroot.jam new file mode 100644 index 00000000..4fb3f288 --- /dev/null +++ b/src/boost/tools/build/test/test2/jamroot.jam @@ -0,0 +1,5 @@ +# Copyright 2002 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +exe foo : foo.cpp ; diff --git a/src/boost/tools/build/test/test_all.py b/src/boost/tools/build/test/test_all.py new file mode 100644 index 00000000..98fcb487 --- /dev/null +++ b/src/boost/tools/build/test/test_all.py @@ -0,0 +1,346 @@ +#!/usr/bin/python + +# Copyright 2002-2005 Dave Abrahams. +# Copyright 2002-2006 Vladimir Prus. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from __future__ import print_function + +import BoostBuild + +import os +import os.path +import sys + +xml = "--xml" in sys.argv +toolset = BoostBuild.get_toolset() + + +# Clear environment for testing. +# +for s in ("BOOST_ROOT", "BOOST_BUILD_PATH", "JAM_TOOLSET", "BCCROOT", + "MSVCDir", "MSVC", "MSVCNT", "MINGW", "watcom"): + try: + del os.environ[s] + except: + pass + +BoostBuild.set_defer_annotations(1) + + +def run_tests(critical_tests, other_tests): + """ + Runs first the critical_tests and then the other_tests. + + Writes the name of the first failed test to test_results.txt. Critical + tests are run in the specified order, other tests are run starting with the + one that failed first on the last test run. + + """ + last_failed = last_failed_test() + other_tests = reorder_tests(other_tests, last_failed) + all_tests = critical_tests + other_tests + + invocation_dir = os.getcwd() + max_test_name_len = 10 + for x in all_tests: + if len(x) > max_test_name_len: + max_test_name_len = len(x) + + pass_count = 0 + failures_count = 0 + + for test in all_tests: + if not xml: + s = "%%-%ds :" % max_test_name_len % test + print(s, end='') + + passed = 0 + try: + __import__(test) + passed = 1 + except KeyboardInterrupt: + """This allows us to abort the testing manually using Ctrl-C.""" + raise + except SystemExit: + """This is the regular way our test scripts are supposed to report + test failures.""" + except: + exc_type, exc_value, exc_tb = sys.exc_info() + try: + BoostBuild.annotation("failure - unhandled exception", "%s - " + "%s" % (exc_type.__name__, exc_value)) + BoostBuild.annotate_stack_trace(exc_tb) + finally: + # Explicitly clear a hard-to-garbage-collect traceback + # related reference cycle as per documented sys.exc_info() + # usage suggestion. + del exc_tb + + if passed: + pass_count += 1 + else: + failures_count += 1 + if failures_count == 1: + f = open(os.path.join(invocation_dir, "test_results.txt"), "w") + try: + f.write(test) + finally: + f.close() + + # Restore the current directory, which might have been changed by the + # test. + os.chdir(invocation_dir) + + if not xml: + if passed: + print("PASSED") + else: + print("FAILED") + BoostBuild.flush_annotations() + else: + rs = "succeed" + if not passed: + rs = "fail" + print(''' +<test-log library="build" test-name="%s" test-type="run" toolset="%s" test-program="%s" target-directory="%s"> +<run result="%s">''' % (test, toolset, "tools/build/v2/test/" + test + ".py", + "boost/bin.v2/boost.build.tests/" + toolset + "/" + test, rs)) + if not passed: + BoostBuild.flush_annotations(1) + print(''' +</run> +</test-log> +''') + sys.stdout.flush() # Makes testing under emacs more entertaining. + BoostBuild.clear_annotations() + + # Erase the file on success. + if failures_count == 0: + open("test_results.txt", "w").close() + + if not xml: + print(''' + === Test summary === + PASS: %d + FAIL: %d + ''' % (pass_count, failures_count)) + + # exit with failure with failures + if failures_count > 0: + sys.exit(1) + +def last_failed_test(): + "Returns the name of the last failed test or None." + try: + f = open("test_results.txt") + try: + return f.read().strip() + finally: + f.close() + except Exception: + return None + + +def reorder_tests(tests, first_test): + try: + n = tests.index(first_test) + return [first_test] + tests[:n] + tests[n + 1:] + except ValueError: + return tests + + +critical_tests = ["unit_tests", "module_actions", "startup_v2", "core_d12", + "core_typecheck", "core_delete_module", "core_language", "core_arguments", + "core_varnames", "core_import_module"] + +# We want to collect debug information about the test site before running any +# of the tests, but only when not running the tests interactively. Then the +# user can easily run this always-failing test directly to see what it would +# have returned and there is no need to have it spoil a possible 'all tests +# passed' result. +if xml: + critical_tests.insert(0, "collect_debug_info") + +tests = ["absolute_sources", + "alias", + "alternatives", + "always", + "bad_dirname", + "build_dir", + "build_file", + "build_hooks", + "build_no", + "builtin_echo", + "builtin_exit", + "builtin_glob", + "builtin_split_by_characters", + "bzip2", + "c_file", + "chain", + "clean", + "command_line_properties", + "composite", + "conditionals", + "conditionals2", + "conditionals3", + "conditionals_multiple", + "configuration", + "configure", + "copy_time", + "core_action_output", + "core_action_status", + "core_actions_quietly", + "core_at_file", + "core_bindrule", + "core_fail_expected", + "core_jamshell", + "core_multifile_actions", + "core_nt_cmd_line", + "core_option_d2", + "core_option_l", + "core_option_n", + "core_parallel_actions", + "core_parallel_multifile_actions_1", + "core_parallel_multifile_actions_2", + "core_scanner", + "core_source_line_tracking", + "core_update_now", + "core_variables_in_actions", + "custom_generator", + "debugger", + "debugger-mi", + "default_build", + "default_features", +# This test is known to be broken itself. +# "default_toolset", + "dependency_property", + "dependency_test", + "disambiguation", + "dll_path", + "double_loading", + "duplicate", + "example_libraries", + "example_make", + "exit_status", + "expansion", + "explicit", + "feature_cxxflags", + "feature_implicit_dependency", + "feature_relevant", + "feature_suppress_import_lib", + "file_types", + "flags", + "generator_selection", + "generators_test", + "implicit_dependency", + "indirect_conditional", + "inherit_toolset", + "inherited_dependency", + "inline", + "libjpeg", + "liblzma", + "libzstd", + "lib_source_property", + "lib_zlib", + "library_chain", + "library_property", + "link", + "load_order", + "loop", + "make_rule", + "message", + "ndebug", + "no_type", + "notfile", + "ordered_include", + "out_of_tree", + "package", + "param", + "path_features", + "prebuilt", + "print", + "project_dependencies", + "project_glob", + "project_id", + "project_root_constants", + "project_root_rule", + "project_test3", + "project_test4", + "property_expansion", + "rebuilds", + "relative_sources", + "remove_requirement", + "rescan_header", + "resolution", + "rootless", + "scanner_causing_rebuilds", + "searched_lib", + "skipping", + "sort_rule", + "source_locations", + "source_order", + "space_in_path", + "stage", + "standalone", + "static_and_shared_library", + "suffix", + "tag", + "test_rc", + "testing", + "timedata", + "toolset_clang_darwin", + "toolset_clang_linux", + "toolset_clang_vxworks", + "toolset_darwin", + "toolset_defaults", + "toolset_gcc", + "toolset_intel_darwin", + "toolset_requirements", + "unit_test", + "unused", + "use_requirements", + "using", + "wrapper", + "wrong_project", + ] + +if os.name == "posix": + tests.append("symlink") + # On Windows, library order is not important, so skip this test. Besides, + # it fails ;-). Further, the test relies on the fact that on Linux, one can + # build a shared library with unresolved symbols. This is not true on + # Windows, even with cygwin gcc. + +# Disable this test until we figure how to address failures due to --as-needed being default now. +# if "CYGWIN" not in os.uname()[0]: +# tests.append("library_order") + +if toolset.startswith("gcc") and os.name != "nt": + # On Windows it's allowed to have a static runtime with gcc. But this test + # assumes otherwise. Hence enable it only when not on Windows. + tests.append("gcc_runtime") + +# PCH test seems broken in strange ways. Disable it. +# if toolset.startswith("gcc") or toolset.startswith("msvc"): +# tests.append("pch") + +# Disable on OSX as it doesn't seem to work for unknown reasons. +if sys.platform != 'darwin': + tests.append("builtin_glob_archive") + +if "--extras" in sys.argv: + tests.append("boostbook") + tests.append("qt4") + tests.append("qt5") + tests.append("example_qt4") + # Requires ./whatever.py to work, so is not guaranteed to work everywhere. + tests.append("example_customization") + # Requires gettext tools. + tests.append("example_gettext") +elif not xml: + print("Note: skipping extra tests") + +run_tests(critical_tests, tests) diff --git a/src/boost/tools/build/test/test_rc.py b/src/boost/tools/build/test/test_rc.py new file mode 100755 index 00000000..56c02b7e --- /dev/null +++ b/src/boost/tools/build/test/test_rc.py @@ -0,0 +1,148 @@ +#!/usr/bin/python + +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests rc toolset behaviour. + +import BoostBuild + + +def included_resource_newer_than_rc_script(): + """ + When a .rc script file includes another resource file - the resource file + being newer than the .rc script file should not cause the .rc script file + to be considered old and force all of its dependents to rebuild. + + """ + toolsetName = "__myDummyResourceCompilerToolset__" + + # Used options rationale: + # + # -d4 & --debug-configuration + # Display additional information in case of test failure. In the past + # we have had testing system issues causing this test to fail + # sporadically for which -d+3 output had been instrumental in getting to + # the root cause (a touched file's timestamp was not as new as it should + # have been). + # + # --ignore-site-config --user-config= + # Disable reading any external Boost Build configuration. This test is + # self sufficient so these options protect it from being adversly + # affected by any local (mis)configuration.. + t = BoostBuild.Tester(["-d4", "--debug-configuration", + "--ignore-site-config", "--user-config=", "toolset=%s" % toolsetName], + pass_toolset=False, use_test_config=False, + translate_suffixes=False) + + # Prepare a dummy toolset so we do not get errors in case the default one + # is not found and that we can test rc.jam functionality without having to + # depend on the externally specified toolset actually supporting it exactly + # the way it is required for this test, e.g. gcc toolset, under some + # circumstances, uses a quiet action for generating its null RC targets. + t.write(toolsetName + ".jam", """\ +import feature ; +import rc ; +import type ; +local toolset-name = "%s" ; +feature.extend toolset : $(toolset-name) ; +rule init ( ) { } +rc.configure dummy-rc-command : <toolset>$(toolset-name) : <rc-type>dummy ; +module rc +{ + rule compile.resource.dummy ( targets * : sources * : properties * ) + { + import common ; + .TOUCH on $(targets) = [ common.file-touch-command ] ; + } + actions compile.resource.dummy { $(.TOUCH) "$(<)" } +} +# Make OBJ files generated by our toolset use the "obj" suffix on all +# platforms. We need to do this explicitly for <target-os> windows & cygwin to +# override the default OBJ type configuration (otherwise we would get +# 'ambiguous key' errors on those platforms). +local rule set-generated-obj-suffix ( target-os ? ) +{ + type.set-generated-target-suffix OBJ : <toolset>$(toolset-name) + <target-os>$(target-os) : obj ; +} +set-generated-obj-suffix ; +set-generated-obj-suffix windows ; +set-generated-obj-suffix cygwin ; +""" % toolsetName) + + t.write( + toolsetName + '.py', +""" +from b2.build import feature, type as type_ +from b2.manager import get_manager +from b2.tools import rc, common + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +toolset_name = "{0}" + +feature.extend('toolset', [toolset_name]) + +def init(*args): + pass + +rc.configure(['dummy-rc-command'], ['<toolset>' + toolset_name], ['<rc-type>dummy']) + +ENGINE.register_action( + 'rc.compile.resource.dummy', + ''' + %s "$(<)" + ''' % common.file_creation_command() +) + +def set_generated_obj_suffix(target_os=''): + requirements = ['<toolset>' + toolset_name] + if target_os: + requirements.append('<target-os>' + target_os) + type_.set_generated_target_suffix('OBJ', requirements, 'obj') + +set_generated_obj_suffix() +set_generated_obj_suffix('windows') +set_generated_obj_suffix('cygwin') +""".format(toolsetName) + ) + + # Prepare project source files. + t.write("jamroot.jam", """\ +ECHO "{{{" [ modules.peek : XXX ] [ modules.peek : NOEXEC ] "}}}" ; +obj xxx : xxx.rc ; +""") + t.write("xxx.rc", '1 MESSAGETABLE "xxx.bin"\n') + t.write("xxx.bin", "foo") + + def test1(n, expect, noexec=False): + params = ["-sXXX=%d" % n] + if noexec: + params.append("-n") + params.append("-sNOEXEC=NOEXEC") + t.run_build_system(params) + t.expect_output_lines("*NOEXEC*", noexec) + obj_file = "xxx_res.obj" + t.expect_output_lines("compile.resource.dummy *%s" % obj_file, expect) + if expect and not noexec: + expect("bin/%s/debug/%s" % (toolsetName, obj_file)) + t.expect_nothing_more() + + def test(n, expect): + test1(n, expect, noexec=True) + test1(n, expect) + + test(1, t.expect_addition) + test(2, None) + t.touch("xxx.bin") + test(3, t.expect_touch) + test(4, None) + + t.cleanup() + + +included_resource_newer_than_rc_script() diff --git a/src/boost/tools/build/test/test_system.html b/src/boost/tools/build/test/test_system.html new file mode 100644 index 00000000..6b1100f3 --- /dev/null +++ b/src/boost/tools/build/test/test_system.html @@ -0,0 +1,618 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" +"http://www.w3.org/TR/html4/strict.dtd"> + +<html> + <head> + <meta name="generator" content= + "HTML Tidy for Linux/x86 (vers 1st March 2002), see www.w3.org"> + <!--tidy options: -i -wrap 78 --> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + + <title>A testing system for Boost.Build</title> +<style type="text/css"> + hr { color: black } + p.revision { text-align: right; font-style: italic } + pre.code { margin-left: 2em } + pre.example { margin-left: 2em; border: solid black thin } + pre.output { margin-left: 2em } + img.banner { border: 0; float: left } + h1 { text-align: right } + br.clear { clear: left } + div.attention { color: red } + +</style> + </head> + + <body> + <p><a href="../../../../index.htm"><img class="banner" height="86" width= + "277" alt="C++ Boost" src="../../../../boost.png"></a></p> + + <h1>A testing system for Boost.Build<br class="clear"> + </h1> + <hr> + + <dl class="page-index"> + <dt><a href="#sec-intro">Introduction for users</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#sec-command-line-options">Command line options</a></dt> + </dl> + </dd> + + <dt><a href="#sec-developers">Introduction for developers</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#sec-intro-changing">Changing the working + directory</a></dt> + + <dt><a href="#sec-intro-examining">Examining the working directory and + changing it</a></dt> + + <dt><a href="#sec-intro-results">Test result</a></dt> + </dl> + </dd> + + <dt><a href="#sec-reference">Reference documentation</a></dt> + + <dd> + <dl class="page-index"> + <dt><a href="#method-__init__">Method __init__</a></dt> + + <dt><a href="#method-set_tree">Method <tt>set_tree</tt></a></dt> + + <dt><a href="#method-write">Method <tt>write</tt></a></dt> + + <dt><a href="#method-copy">Method <tt>copy</tt></a></dt> + + <dt><a href="#method-touch">Method <tt>touch</tt></a></dt> + + <dt><a href="#method-run_build_system">Method + <tt>run_build_system</tt></a></dt> + + <dt><a href="#method-read">Method <tt>read</tt></a></dt> + + <dt><a href="#method-read_and_strip">Method + <tt>read_and_strip</tt></a></dt> + + <dt><a href="#methods-expectations">Methods for declaring + expectations</a></dt> + + <dt><a href="#methods-ignoring">Methods for ignoring + changes</a></dt> + + <dt><a href="#methods-result">Methods for explicitly specifying + results</a></dt> + + <dt><a href="#class-list">Helper class <tt>List</tt></a></dt> + </dl> + </dd> + </dl> + <hr> + + <h2><a name="sec-intro">Introduction for users</a></h2> + + <p>The testing system for Boost.Build is a small set of Python modules and + scripts for automatically testing user-obversable behaviour. It uses + components from testing systems of <a href="http://www.scons.org">Scons</a> + and <a href="http://subversion.tigris.org">Subversion</a>, together with + some additional functionality.</p> + + <p>To run the tests you need to:</p> + + <ol> + <li>Get the source tree of Boost.Build (located at <tt>tools/build</tt> + in Boost)</li> + + <li>Have <a href="http://www.python.org">Python</a> installed. Version + 2.1 is known to work.</li> + + <li>Build Boost.Jam. See <a href= + "../engine/index.html">$boost_build_root/engine/index.html</a> for + instructions.</li> + + <li>Configure at least one toolset. You can edit <tt>site-config.jam</tt> + or <tt>user-config.jam</tt> to add new toolsets. Or you can create file + <tt>test-config.jam</tt> in <tt>$boost_build_root/test</tt> directory. In + this case, <tt>site-config.jam</tt> and <tt>user-config.jam</tt> will be + ignored for testing.</li> + </ol> + + <p>When all is set, you can run all the tests using the <tt>test_all.py</tt> + script or you can run a specific test by starting its Python script + directly.</p> + + <p>Examples:</p> + +<pre class="code"> +python test_all.py +python generators_test.py +</pre> + + <p>If everything is OK, you will see a list of passed tests. Otherwise, a + failure will be reported.</p> + + <h3><a name="sec-command-line-options">Command line options</a></h3> + + <p>Test scripts will use the toolset you configured to be the default or + you can specify a specific one on the command line:</p> + +<pre class="code"> +python test_all.py borland +python generators_test.py msvc-7.1 +</pre> + + <p>Other test script flags you can specify on the command line are:</p> + + <ul> + <li><tt>--default-bjam</tt> -- By default the test system will use the + Boost Jam executable found built in its default development build + location. This option makes it use the default one available on your + system, i.e. the one found in the system path.</li> + + <li><tt>--preserve</tt> -- In case of a failed test its working + directory will be copied to the "failed_test" directory under the + current directory.</li> + + <li><tt>--verbose</tt> -- Makes the test system and the run build system + display additional output. Note though that this may cause tests that + check the build system output to fail.</li> + </ul> + + <h2><a name="sec-developers">Introduction for developers</a></h2> + + <p>It is suggested that every new functionality come together with tests, + and that bugfixes are accompanied by tests. There's no need to say that + tests are good, but two points are extremely important:</p> + + <ul> + <li>For an interpreted language like Jam, without any static checks, + testing is simply the only sefeguard we can have.</li> + + <li>Good tests allow us to change internal design much more safely, and we + have not gotten everything nailed down yet.</li> + </ul> + + <p>Adding a new test is simple:</p> + + <ol> + <li>Go to <tt>$boost_build_root/test/test_all.py</tt> and add new test + name to the list at the end of the file. Suppose the test name is "hello". + </li> + + <li>Add a new python module, in this example "hello.py", to do the actual + testing.</li> + </ol> + + <p>The module, in general will perform these basic actions:</p> + + <ol> + <li>Set up the initial working directory state</li> + + <li> + Run the build system and check the results: + + <ol> + <li>generated output,</li> + + <li>changes made to the working directory,</li> + + <li>new content of the working directory.</li> + </ol> + </li> + + <li>Add, remove or touch files or change their content and then repeat + the previous step until satisfied.</li> + + <li>Clean up</li> + </ol> + + <p>The "hello.py" module might contain:</p> +<pre class="example"> +from BoostBuild import List + +# Create a temporary working directory +t = BoostBuild.Tester() + +# Create the needed files +t.write("jamroot.jam", "") +t.write("jamfile.jam", """ +exe hello : hello.cpp ; +""") +t.write("hello.cpp", """ +int main() +{ + return 0; +} + +""") + +t.run_build_system() + +# First, create a list of three pathnames. +file_list = List("bin/$toolset/debug/") * List("hello.exe hello.obj") +# Second, assert that those files were added as result of the last build system invocation. +t.expect_addition(file_list) + +# Invoke the build system once again. +t.run_build_system("clean") +# Check if the files added previously were removed. +t.expect_removal(file_list) + +# Remove temporary directories +t.cleanup() +</pre> + + <p>The <tt>test</tt> directory contains a file "template.py" which can be + used as a start for your own tests.</p> + + <p>Overview of the most important methods of class <tt>Tester</tt> follows. + </p> + + <h3><a name="sec-intro-changing">Changing the working directory</a></h3> + + <p>The class <tt>Tester</tt> creates a temporary directory in its + constructor and changes to that directory. It can be modified by calling + these methods:</p> + + <ul> + <li><tt>set_tree</tt> -- sets the content of the working directory to be + equal to the content of the specified directory. This method is + preferable when directory tree for testing is large.</li> + + <li><tt>write</tt> -- sets the content of file in a working directory. + This is optimal if you want to create a directory tree with 3-4 small + files.</li> + + <li><tt>touch</tt> -- changes the modification times of a file</li> + </ul> + + <h3><a name="sec-intro-examining">Examining the working directory and + changing it</a></h3> + + <p>The method <tt>read</tt>, inherited from the <tt>TestCmd</tt> class, can + be used to read any file in the working directory and check its content. + <tt>Tester</tt> adds another method for tracking changes. Whenever the build + system is run (using <a href="#method-run_build_system"><tt>run_build_system + </tt></a>), the working dir state before and after running is recorded. In + addition, difference between the two states -- i.e. lists of files that were + added, removed, modified or touched -- are stored in two member variables - + <tt>tree_difference</tt> and <tt>unexpected_difference</tt>.</p> + + <p>After than, the test author may specify that some change is expected, for + example, by calling <tt>expect_addition("foo")</tt>. This call will check if + the file was indeed added, and if so, will remove its name from the list of + added files in <tt>unexpected_difference</tt>. Likewise, it is possible to + specify that some changes are not interesting, for example a call to + <tt>ignore("*.obj")</tt> will just remove every file with the ".obj" + extension from <tt>unexpected_difference</tt>.</p> + + <p>When test has finished with expectations and ignoring, the member + <tt>unexpected_difference</tt> will contain the list of all changes not yet + accounted for. It is possible to assure that this list is empty by calling + the <tt>expect_nothing_more</tt> member function.</p> + + <h3><a name="sec-intro-results">Test result</a></h3> + + <p>Any of the <tt>expect*</tt> methods below will fail the test if the + expectation is not met. It is also possible to perform manually arbitrary + test and explicitly cause the test to either pass or fail. Ordinary + filesystem functions can be used to work with the directory tree. Methods + <tt>pass_test</tt> and <tt>fail_test</tt> are used to explicitly give the + test outcome.</p> + + <p>Typically, after test termination, the working directory is erased. See + the <a href="#sec-command-line-options">"--preserve" command line option</a> + for information on how to preserve the working directory content for failed + tests for debugging purposes.</p> + + <h2 id="sec-reference">Reference documentation</h2> + + <p>The test system is composed of class <tt>Tester</tt>, derived form + <tt>TestCmd.TestCmd</tt>, and helper class <tt>List</tt>. <tt>Tester</tt> + and <tt>List</tt> methods are described below.</p> + + <p>The documentation frequently refers to <tt>filename</tt>. In all cases, + files are specified in unix style: a sequence of components, separated by + "/". This is true on all platforms. In some contexts a list of files is + allowed. In those cases any object with a sequence interface is allowed.</p> + + <h3><a name="method-__init__">Method <tt>__init__(self, arguments="", + executable="bjam", match=TestCmd.match_exact, boost_build_path=None, + translate_suffixes=True, pass_toolset=True, use_test_config=True, + ignore_toolset_requirements=True, workdir="", **keywords)</tt></a></h3> + + <p><b>Optional arguments:</b></p> + + <ul> + <li><tt>arguments</tt> + -- Arguments passed to the run executable.</li> + <li><tt>executable</tt> + -- Name of the executable to invoke.</li> + <li><tt>match</tt> + -- Function to use for compating actual and expected file contents. + </li> + <li><tt>boost_build_path</tt> + -- Boost build path to be passed to the run executable.</li> + <li><tt>translate_suffixes</tt> + -- Whether to update suffixes on the the file names passed from the + test script so they match those actually created by the current + toolset. For example, static library files are specified by using + the .lib suffix but when the 'gcc' toolset is used it actually + creates them using the .a suffix.</li> + <li><tt>pass_toolset</tt> + -- Whether the test system should pass the specified toolset to the + run executable.</li> + <li><tt>use_test_config</tt> + -- Whether the test system should tell the run executable to read in + the test_config.jam configuration file.</li> + <li><tt>ignore_toolset_requirements</tt> + -- Whether the test system should tell the run executable to ignore + toolset requirements.</li> + <li><tt>workdir</tt> + -- Indicates an absolute directory where the test will be run from. + </li> + </ul> + + <p><b>Optional arguments inherited from the base class:</b></p> + + <ul> + <li><tt>description</tt> + -- Test description string displayed in case of a failed test.</li> + <li><tt>subdir</tt> + -- List of subdirectories to automatically create under the working + directory. Each subdirectory needs to be specified separately + parent coming before its child.</li> + <li><tt>verbose</tt> + -- Flag that may be used to enable more verbose test system output. + Note that it does not also enable more verbose build system output + like the <a href="#sec-command-line-options">"--verbose" command + line option</a> does.</li> + </ul> + + <p><b>Effects:</b></p> + + <ol> + <li>Remembers the current working directory in member + <tt>original_workdir</tt>.</li> + + <li>Determines the location of the executable (<code>bjam</code> by + default) and build system files, assuming that the current directory is + <tt>tools/build/test</tt>. Formulates jam invocation command, which + will include explicit setting for the <tt>BOOST_BUILD_PATH</tt> variable + and arguments passed to this methods, if any. This command will be used + by subsequent invocation of <a href="#method-run_build_system"><tt> + run_build_system</tt></a>. Finally, initializes the base class.</li> + + <li>Changes the current working directory to the temporary working + directory created by the base constructor.</li> + + <li>If you want to run a test in an existing directory, pass it as + <tt>workdir</tt>.</li> + + <li> Most parameters passed to this constructor function may be overruled + for each specific test system run using <a href= + "#method-run_build_system"><tt>run_build_system</tt></a> parameters. + </ol> + + <h3><a name="method-set_tree">Method <tt>set_tree(self, + tree_location)</tt></a></h3> + + <p><b>Effects:</b></p> + + <p>Replaces the content of the current working directory with the content + of directory at <tt>tree_location</tt>. If <tt>tree_location</tt> is not + absolute pathname, it will be treated as relative to + <tt>self.original_workdir</tt>. This methods also explicitly makes the + copied files writeable.</p> + + <h3><a name="method-write">Method <tt>write(self, name, + content)</tt></a></h3> + + <p><b>Effects:</b></p> + + <p>Writes the specified content to the file given by <tt>name</tt> under + the temporary working directory. If the file already exists, it is + overwritten. Any required directories are automatically created.</p> + + <h3><a name="method-copy">Method <tt>copy(self, src, dst)</tt></a></h3> + + <p><b>Effects:</b></p> + + <p>Equvivalent to <tt>self.write(self.read(src), dst)</tt>.</p> + + <h3><a name="method-touch">Method <tt>touch(self, names)</tt></a></h3> + + <p><b>Effects:</b></p> + + <p>Sets the access and modification times for all files in <tt>names</tt> to + the current time. All the elements in <tt>names</tt> should be relative + paths.</p> + + <h3><a name="method-run_build_system">Method <tt>run_build_system(self, + extra_args="", subdir="", stdout=None, stderr="", status=0, match=None, + pass_toolset=None, use_test_config=None, ignore_toolset_requirements=None, + expected_duration=None, **kw)</tt></a></h3> + + <p><b>Effects:</b></p> + + <ol> + <li>Stores the state of the working directory in + <tt>self.previous_tree</tt>.</li> + + <li>Changes to <tt>subdir</tt>, if it is specified. It is relative to + the <tt>original_workdir</tt> or the workdir specified in + <tt>__init</tt>.</li> + + <li>Invokes the <tt>bjam</tt> executable, passing <tt>extra_args</tt> + to it. The binary should be located under + <tt><test_invocation_dir>/../jam/src/bin.<platform></tt>. + This is to make sure tests use the version of jam build from CVS.</li> + + <li>Compares the stdout, stderr and exit status of build system + invocation with values to appropriate parameters, if they are not + <tt>None</tt>. If any difference is found, the test fails.</li> + + <li>If the <tt>expected_duration</tt> parameter is specified then it + represents the maximal allowed time in seconds for the test to run. The + test will be marked as failed if its duration is greater than the given + <tt>expected_duration</tt> parameter value.</li> + + <li>Stores the new state of the working directory in <tt>self.tree</tt>. + Computes the difference between previous and current trees and stores them + in variables <tt>self.tree_difference</tt> and + <tt>self.unexpected_difference</tt>. Both variables are instances of class + <tt>tree.Trees_different</tt>, which have four attributes: + <tt>added_files</tt>, <tt>removed_files</tt>, <tt>modified_files</tt> and + <tt>touched_files</tt>. Each is a list of strings.</p></li> + </ol> + + <h3><a name="method-read">Method <tt>read(self, name)</tt></a></h3> + + <p><b>Effects:</b></p> + + <p>Read the specified file and returns it content. Raises an exception is + the file is absent.</p> + + <h3><a name="method-read_and_strip">Method <tt>read_and_strip(self, name) + </tt></a></h3> + + <p><b>Effects:</b></p> + + <p>Read the specified file and returns it content, after removing trailing + whitespace from every line. Raises an exception is the file is absent.</p> + + <p><b>Rationale:</b></p> + + <p>Although this method is questionable, there are a lot of cases when jam + or shells it uses insert spaces. It seems that introducing this method is + much simpler than dealing with all those cases.</p> + + <h3><a name="methods-expectations">Methods for declaring expectations</a> + </h3> + + <p>Accordingly to the number of changes kinds that are detected, there are + four methods that specify that test author expects a specific change to + occur. They check <tt>self.unexpected_difference</tt>, and if the change is + present there, it is removed. Otherwise, test fails.</p> + + <p>Each method accepts a list of names. Those names use <tt>/</tt> path + separator on all systems. Additionally, the test system translates suffixes + appropriately. For the test to be portable, suffixes should use Windows + convention: <tt>exe</tt> for executables, <tt>dll</tt> for dynamic libraries + and <tt>lib</tt> for static libraries. Lastly, the string "$toolset" in file + names is replaced by the name of tested toolset.</p> + + <p><b>Note:</b> The <tt>List</tt> helper class might be useful to create + lists of names.</p> + + <p><b>Note:</b> The file content can be examined using the + <tt>TestCmd.read</tt> function.</p> + + <p>The members are:</p> + + <ul> + <li>expect_addition</li> + <li>expect_removal</li> + <li>expect_modification</li> + <li>expect_nothing</li> + </ul> + + <p>Note that <tt>expect_modification</tt> is used to check that a either + file content or timestamp has changed. The rationale is that some compilers + change content even if sources does not change, and it's easier to have a + method which checks for both content and time changes.</p> + + <p>There's also a member <tt>expect_nothing_more</tt>, which checks that all + the changes are either expected or ignored, in other words that + <tt>unexpected_difference</tt> is empty by now.</p> + + <p>Lastly, there's a method to compare file content with expected content: + </p> + <tt>expect_content(self, name, content, exact=0)</tt> + + <p>The method fails the test if the content of file identified by 'name' is + different from 'content'. If 'exact' is true, the file content is used + as-is, otherwise, two transformations are applied:</p> + + <ul> + <li>The <tt>read_and_strip</tt> method is used to read the file, which + removes trailing whitespace</li> + + <li>Each backslash in the file content is converted to forward slash.</li> + </ul> + + <h3><a name="methods-ignoring">Methods for ignoring changes</a></h3> + + <p>There are five methods which ignore changes made to the working tree. + They silently remove elements from <tt>self.unexpected_difference</tt>, and + don't generate error if element is not found. They accept shell style + wildcard.</p> + + <p>The following methods correspond to four kinds of changes:</p> + + <ul> + <li>ignore_addition(self, wildcard)</li> + <li>ignore_removal(self, wildcard)</li> + <li>ignore_modification(self, wildcard)</li> + <li>ignore_touch(self, wildcard)</li> + </ul> + + <p>The method <tt>ignore(self, wildcard)</tt> ignores all the changes made + to files that match a wildcard.</p> + + <h3><a name="methods-result">Methods for explicitly specifying results</a> + </h3> + + <h4>Method <tt>pass_test(self, condition=1)</tt></h4> + + <div class="attention"> + At this moment, the method should not be used. + </div> + + <h4>Method <tt>fail_test(self, condition=1)</tt></h4> + + <p><b>Effects:</b> Cause the test to fail if <tt>condition</tt> is true.</p> + + <h3><a name="class-list">Helper class <tt>List</tt></a></h3> + The class has sequence interface and two additional methods. + + <h4>Method <tt>__init__(self, string)</tt></h4> + + <p><b>Effects:</b> Splits the string on unescaped spaces and tabs. The split + components can further be retrieved using standard sequence access.</p> + + <h4>Method <tt>__mul__(self, other)</tt></h4> + + <p><b>Effects:</b> Returns an <tt>List</tt> instance, which elements are all + possible concatenations of two string, first of which is from <tt>self</tt>, + and second of which is from <tt>other</tt>.</p> + + <p>The class also defines <tt>__str__</tt> and <tt>__repr__</tt> methods. + Finally, there's <tt>__coerce__</tt> method which allows to convert strings + to instances of <tt>List</tt>.</p> + + <p><b>Example:</b></p> +<pre> + l = "a b" * List("c d") + for e in l: + print e +</pre> + + <p>will output:</p> +<pre> + ac + ad + bc + bd + +</pre> + <hr> + <p class="revision">Last modified: May 02, 2008</p> + <p>© Copyright Vladimir Prus 2002, 2003, 2004, 2005.<br> + © Copyright Jurko Gospodnetic 2008.<br> + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)</p> + </body> +</html> diff --git a/src/boost/tools/build/test/testing.py b/src/boost/tools/build/test/testing.py new file mode 100755 index 00000000..74104012 --- /dev/null +++ b/src/boost/tools/build/test/testing.py @@ -0,0 +1,535 @@ +#!/usr/bin/python + +# Copyright 2008 Jurko Gospodnetic +# Copyright 2017 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Tests different aspects of Boost Builds automated testing support. + +import BoostBuild +import TestCmd + +def test_run(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +run pass.cpp ; +run fail-compile.cpp ; +run fail-link.cpp ; +run fail-run.cpp ; +""") + + t.run_build_system(status=1) + t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.output") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.run") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj") + + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.exe") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.output") + + t.expect_nothing_more() + + t.cleanup() + +def test_run_fail(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +run-fail pass.cpp ; +run-fail fail-compile.cpp ; +run-fail fail-link.cpp ; +run-fail fail-run.cpp ; +""") + + t.run_build_system(status=1) + t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.output") + + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj") + + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.exe") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.output") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.run") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test") + + t.expect_nothing_more() + + t.cleanup() + +def test_run_change(): + """Tests that the test file is removed when a test fails after it + previously passed.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() { return 1; }\n") + t.write("fail-compile.cpp", "int main() {}\n") + t.write("fail-link.cpp", "int main() {}\n") + t.write("fail-run.cpp", "int main() {}\n") + + t.write("Jamroot.jam", """import testing ; +run-fail pass.cpp ; +run fail-compile.cpp ; +run fail-link.cpp ; +run fail-run.cpp ; +""") + t.run_build_system() + # Sanity check + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test") + t.expect_output_lines("...failed*", False) + + # Now make them fail + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + t.run_build_system(status=1) + + t.expect_removal("bin/pass.test/$toolset/debug*/pass.test") + t.expect_removal("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + t.expect_removal("bin/fail-link.test/$toolset/debug*/fail-link.test") + t.expect_removal("bin/fail-run.test/$toolset/debug*/fail-run.test") + + t.cleanup() + +def test_run_path(): + """Tests that run can find shared libraries even without + hardcode-dll-paths. Important: The library is in neither the + current working directory, nor any system path, nor the same + directory as the executable, so it should never be found without + help from Boost.Build.""" + t = BoostBuild.Tester(["hardcode-dll-paths=false"], use_test_config=False) + + t.write("l.cpp", """ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +f() {} +""") + t.write("pass.cpp", "void f(); int main() { f(); }\n") + + t.write("Jamroot.jam", """import testing ; +lib l : l.cpp : <link>shared ; +run pass.cpp l ; +""") + + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/l.obj") + t.expect_addition("bin/$toolset/debug*/l.dll") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.output") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.run") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + + t.cleanup() + +def test_run_args(): + """Tests the handling of args and input-files""" + t = BoostBuild.Tester(use_test_config=False) + t.write("test.cpp", """ +#include <iostream> +#include <fstream> +int main(int argc, const char ** argv) +{ + for(int i = 1; i < argc; ++i) + { + if(argv[i][0] == '-') + { + std::cout << argv[i] << std::endl; + } + else + { + std::ifstream ifs(argv[i]); + std::cout << ifs.rdbuf(); + } + } +} +""") + t.write("input1.in", "first input\n") + t.write("input2.in", "second input\n") + t.write("Jamroot.jam", """import testing ; +import common ; +# FIXME: The order actually depends on the lexigraphical +# ordering of the virtual target objects, which is just +# crazy. Switch the order of input1.txt and input2.txt +# to make this fail. Joining the arguments with && might +# work, but might get a bit complicated to implement as +# dependency properties do not currently support &&. +make input1.txt : input1.in : @common.copy ; +make input2.txt : input2.in : @common.copy ; +run test.cpp : -y -a : input1.txt input2.txt ; +""") + t.run_build_system() + t.expect_content("bin/test.test/$toolset/debug*/test.output", """\ +-y +-a +first input +second input + +EXIT STATUS: 0 +""") + t.cleanup() + +def test_link(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +link pass.cpp ; +link fail-compile.cpp ; +link fail-link.cpp ; +link fail-run.cpp ; +""") + + t.run_build_system(status=1) + t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj") + + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.exe") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test") + + t.expect_nothing_more() + + t.cleanup() + +def test_link_fail(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +link-fail pass.cpp ; +link-fail fail-compile.cpp ; +link-fail fail-link.cpp ; +link-fail fail-run.cpp ; +""") + + t.run_build_system(status=1) + t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj") + + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj") + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.exe") + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test") + + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj") + + t.expect_nothing_more() + + t.cleanup() + +def test_link_change(): + """Tests that the test file is removed when a test fails after it + previously passed.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-compile.cpp", "int main() {}\n") + t.write("fail-link.cpp", "int main() {}\n") + + t.write("Jamroot.jam", """import testing ; +link-fail pass.cpp ; +link fail-compile.cpp ; +link fail-link.cpp ; +""") + t.run_build_system() + # Sanity check + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test") + t.expect_output_lines("...failed*", False) + + # Now make them fail + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.run_build_system(status=1) + + t.expect_removal("bin/pass.test/$toolset/debug*/pass.test") + t.expect_removal("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + t.expect_removal("bin/fail-link.test/$toolset/debug*/fail-link.test") + + t.cleanup() + +def test_compile(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +compile pass.cpp ; +compile fail-compile.cpp ; +compile fail-link.cpp ; +compile fail-run.cpp ; +""") + + t.run_build_system(status=1) + t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj") + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj") + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test") + + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test") + + t.expect_nothing_more() + + t.cleanup() + +def test_compile_fail(): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +compile-fail pass.cpp ; +compile-fail fail-compile.cpp ; +compile-fail fail-link.cpp ; +compile-fail fail-run.cpp ; +""") + + t.run_build_system(status=1) + t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.obj") + t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + + t.expect_nothing_more() + + t.cleanup() + +def test_compile_change(): + """Tests that the test file is removed when a test fails after it + previously passed.""" + + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass.cpp", "#error expected to fail\n") + t.write("fail-compile.cpp", "int main() {}\n") + + t.write("Jamroot.jam", """import testing ; +compile-fail pass.cpp ; +compile fail-compile.cpp ; +""") + t.run_build_system() + # Sanity check + t.expect_addition("bin/pass.test/$toolset/debug*/pass.test") + t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + t.expect_output_lines("...failed*", False) + + # Now make them fail + t.write("pass.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.run_build_system(status=1) + + t.expect_removal("bin/pass.test/$toolset/debug*/pass.test") + t.expect_removal("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + + t.cleanup() + +def test_remove_test_targets(option): + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass-compile.cpp", "int main() {}\n") + t.write("pass-link.cpp", "int main() {}\n") + t.write("pass-run.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + t.write("source.cpp", "int f();\n") + + t.write("Jamroot.jam", """import testing ; +obj source.o : source.cpp ; +compile pass-compile.cpp ; +link pass-link.cpp source.o ; +run pass-run.cpp source.o ; +compile-fail fail-compile.cpp ; +link-fail fail-link.cpp ; +run-fail fail-run.cpp ; +""") + + t.run_build_system([option]) + + t.expect_addition("bin/$toolset/debug*/source.obj") + + t.expect_addition("bin/pass-compile.test/$toolset/debug*/pass-compile.test") + + t.expect_addition("bin/pass-link.test/$toolset/debug*/pass-link.test") + + t.expect_addition("bin/pass-run.test/$toolset/debug*/pass-run.output") + t.expect_addition("bin/pass-run.test/$toolset/debug*/pass-run.run") + t.expect_addition("bin/pass-run.test/$toolset/debug*/pass-run.test") + + t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test") + + t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test") + + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.output") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.run") + t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test") + + t.expect_nothing_more() + + t.cleanup() + +def test_dump_tests(): + """Tests the output of the --dump-tests option""" + t = BoostBuild.Tester(use_test_config=False) + + t.write("pass-compile.cpp", "int main() {}\n") + t.write("pass-link.cpp", "int main() {}\n") + t.write("pass-run.cpp", "int main() {}\n") + t.write("fail-compile.cpp", "#error expected to fail\n") + t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n") + t.write("fail-run.cpp", "int main() { return 1; }\n") + + t.write("Jamroot.jam", """import testing ; +run pass-run.cpp ; +run-fail fail-run.cpp ; +link pass-link.cpp ; +link-fail fail-link.cpp ; +compile pass-compile.cpp ; +compile-fail fail-compile.cpp ; +build-project libs/any/test ; +build-project libs/any/example ; +build-project libs/any ; +build-project tools/bcp/test ; +build-project tools/bcp/example ; +build-project subdir/test ; +build-project status ; +build-project outside/project ; +""") + def write_subdir(dir): + t.write(dir + "/test.cpp", "int main() {}\n") + t.write(dir + "/Jamfile", "run test.cpp ;") + write_subdir("libs/any/test") + write_subdir("libs/any/example") + write_subdir("libs/any") + write_subdir("tools/bcp/test") + write_subdir("tools/bcp/example") + write_subdir("status") + write_subdir("subdir/test") + t.write("outside/other/test.cpp", "int main() {}\n") + t.write("outside/project/Jamroot", "run ../other/test.cpp ;") + t.run_build_system(["--dump-tests", "-n", "-d0"], + match=TestCmd.match_re, stdout= +"""boost-test\(RUN\) ".*/pass-run" : "pass-run\.cpp" +boost-test\(RUN_FAIL\) ".*/fail-run" : "fail-run\.cpp" +boost-test\(LINK\) ".*/pass-link" : "pass-link\.cpp" +boost-test\(LINK_FAIL\) ".*/fail-link" : "fail-link\.cpp" +boost-test\(COMPILE\) ".*/pass-compile" : "pass-compile\.cpp" +boost-test\(COMPILE_FAIL\) ".*/fail-compile" : "fail-compile\.cpp" +boost-test\(RUN\) "any/test" : "libs/any/test\.cpp" +boost-test\(RUN\) "any/test" : "libs/any/test/test\.cpp" +boost-test\(RUN\) "any/test" : "libs/any/example/test\.cpp" +boost-test\(RUN\) "bcp/test" : "tools/bcp/test/test\.cpp" +boost-test\(RUN\) "bcp/test" : "tools/bcp/example/test\.cpp" +boost-test\(RUN\) ".*/subdir/test/test" : "subdir/test/test\.cpp" +boost-test\(RUN\) "test" : "status/test\.cpp" +boost-test\(RUN\) ".*/outside/project/test" : "../other/test.cpp" +""") + t.cleanup() + +################################################################################ +# +# test_files_with_spaces_in_their_name() +# -------------------------------------- +# +################################################################################ + +def test_files_with_spaces_in_their_name(): + """Regression test making sure test result files get created correctly when + testing files with spaces in their name. + """ + + t = BoostBuild.Tester(use_test_config=False) + + t.write("valid source.cpp", "int main() {}\n"); + + t.write("invalid source.cpp", "this is not valid source code"); + + t.write("jamroot.jam", """ +import testing ; +testing.compile "valid source.cpp" ; +testing.compile-fail "invalid source.cpp" ; +""") + + t.run_build_system(status=0) + t.expect_addition("bin/invalid source.test/$toolset/debug*/invalid source.obj") + t.expect_addition("bin/invalid source.test/$toolset/debug*/invalid source.test") + t.expect_addition("bin/valid source.test/$toolset/debug*/valid source.obj") + t.expect_addition("bin/valid source.test/$toolset/debug*/valid source.test") + + t.expect_content("bin/valid source.test/$toolset/debug*/valid source.test", \ + "passed" ) + t.expect_content( \ + "bin/invalid source.test/$toolset/debug*/invalid source.test", \ + "passed" ) + t.expect_content( \ + "bin/invalid source.test/$toolset/debug*/invalid source.obj", \ + "failed as expected" ) + + t.cleanup() + + +################################################################################ +# +# main() +# ------ +# +################################################################################ + +test_run() +test_run_fail() +test_run_change() +test_run_path() +test_run_args() +test_link() +test_link_fail() +test_link_change() +test_compile() +test_compile_fail() +test_compile_change() +test_remove_test_targets("--remove-test-targets") +test_remove_test_targets("preserve-test-targets=off") +test_dump_tests() +test_files_with_spaces_in_their_name() diff --git a/src/boost/tools/build/test/timedata.py b/src/boost/tools/build/test/timedata.py new file mode 100644 index 00000000..32cec265 --- /dev/null +++ b/src/boost/tools/build/test/timedata.py @@ -0,0 +1,178 @@ +#!/usr/bin/python + +# Copyright 2005 David Abrahams +# Copyright 2008, 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Tests the build step timing facilities. + +# TODO: Missing tests: +# 1. 'time' target with a source target representing more than one virtual +# target. This happens in practice, e.g. when using the time rule on a msvc +# exe target whose generator actually constructs an EXE and a PDB target. +# When this is done - only the main virtual target's constructing action +# should be timed. +# 2. 'time' target with a source target representing a virtual target that +# actually gets built by multiple actions run in sequence. In that case a +# separate timing result should be reported for each of those actions. This +# happens in practice, e.g. when using the time rule on a msvc exe target +# which first gets created as a result of some link action and then its +# manifest gets embedded inside it as a resource using a separate action +# (assuming an appropriate property has been set for this target - see the +# msvc module for details). + +import BoostBuild +import re + + +############################################################################### +# +# basic_jam_action_test() +# ----------------------- +# +############################################################################### + +def basic_jam_action_test(): + """Tests basic Jam action timing support.""" + + t = BoostBuild.Tester(pass_toolset=0) + + t.write("file.jam", """\ +rule time +{ + DEPENDS $(<) : $(>) ; + __TIMING_RULE__ on $(>) = record_time $(<) ; + DEPENDS all : $(<) ; +} + +actions time +{ + echo $(>) user: $(__USER_TIME__) system: $(__SYSTEM_TIME__) clock: $(__CLOCK_TIME__) + echo timed from $(>) >> $(<) +} + +rule record_time ( target : source : start end user system clock ) +{ + __USER_TIME__ on $(target) = $(user) ; + __SYSTEM_TIME__ on $(target) = $(system) ; + __CLOCK_TIME__ on $(target) = $(clock) ; +} + +rule make +{ + DEPENDS $(<) : $(>) ; +} + +actions make +{ + echo made from $(>) >> $(<) +} + +time foo : bar ; +make bar : baz ; +""") + + t.write("baz", "nothing") + + expected_output = """\ +\.\.\.found 4 targets\.\.\. +\.\.\.updating 2 targets\.\.\. +make bar +time foo +bar +user: [0-9\.]+ +system: +[0-9\.]+ +clock: +[0-9\.]+ * +\.\.\.updated 2 targets\.\.\.$ +""" + + t.run_build_system(["-ffile.jam", "-d+1"], stdout=expected_output, + match=lambda actual, expected: re.search(expected, actual, re.DOTALL)) + t.expect_addition("foo") + t.expect_addition("bar") + t.expect_nothing_more() + + t.cleanup() + + +############################################################################### +# +# boost_build_testing_support_timing_rule(): +# ------------------------------------------ +# +############################################################################### + +def boost_build_testing_support_timing_rule(): + """ + Tests the target build timing rule provided by the Boost Build testing + support system. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("aaa.cpp", "int main() {}\n") + + t.write("jamroot.jam", """\ +import testing ; +exe my-exe : aaa.cpp ; +time my-time : my-exe ; +""") + + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/aaa.obj") + t.expect_addition("bin/$toolset/debug*/my-exe.exe") + t.expect_addition("bin/$toolset/debug*/my-time.time") + + t.expect_content_lines("bin/$toolset/debug*/my-time.time", + "user: *[0-9] seconds") + t.expect_content_lines("bin/$toolset/debug*/my-time.time", + "system: *[0-9] seconds") + t.expect_content_lines("bin/$toolset/debug*/my-time.time", + "clock: *[0-9] seconds") + + t.cleanup() + + +############################################################################### +# +# boost_build_testing_support_timing_rule_with_spaces_in_names() +# -------------------------------------------------------------- +# +############################################################################### + +def boost_build_testing_support_timing_rule_with_spaces_in_names(): + """ + Tests the target build timing rule provided by the Boost Build testing + support system when used with targets contining spaces in their names. + + """ + t = BoostBuild.Tester(use_test_config=False) + + t.write("aaa bbb.cpp", "int main() {}\n") + + t.write("jamroot.jam", """\ +import testing ; +exe "my exe" : "aaa bbb.cpp" ; +time "my time" : "my exe" ; +""") + + t.run_build_system() + t.expect_addition("bin/$toolset/debug*/aaa bbb.obj") + t.expect_addition("bin/$toolset/debug*/my exe.exe") + t.expect_addition("bin/$toolset/debug*/my time.time") + + t.expect_content_lines("bin/$toolset/debug*/my time.time", "user: *") + t.expect_content_lines("bin/$toolset/debug*/my time.time", "system: *") + + t.cleanup() + + +############################################################################### +# +# main() +# ------ +# +############################################################################### + +basic_jam_action_test() +boost_build_testing_support_timing_rule() +boost_build_testing_support_timing_rule_with_spaces_in_names()
\ No newline at end of file diff --git a/src/boost/tools/build/test/toolset-mock/Jamroot.jam b/src/boost/tools/build/test/toolset-mock/Jamroot.jam new file mode 100644 index 00000000..fd5f7907 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/Jamroot.jam @@ -0,0 +1,8 @@ +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +lib l1 : lib.cpp ; +exe test : main.cpp l1 ; diff --git a/src/boost/tools/build/test/toolset-mock/lib.cpp b/src/boost/tools/build/test/toolset-mock/lib.cpp new file mode 100644 index 00000000..1ba30e32 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/lib.cpp @@ -0,0 +1,7 @@ +// Copyright (c) 2017 Steven Watanabe +// +// Distributed under the Boost Software License Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +int f() {} diff --git a/src/boost/tools/build/test/toolset-mock/main.cpp b/src/boost/tools/build/test/toolset-mock/main.cpp new file mode 100644 index 00000000..0fc8b9a7 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/main.cpp @@ -0,0 +1,7 @@ +// Copyright (c) 2017 Steven Watanabe +// +// Distributed under the Boost Software License Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +int main() {} diff --git a/src/boost/tools/build/test/toolset-mock/project-config.jam b/src/boost/tools/build/test/toolset-mock/project-config.jam new file mode 100644 index 00000000..30a9e941 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/project-config.jam @@ -0,0 +1,43 @@ +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import modules ; +import os ; + +path-constant here : . ; + +local PYTHON = [ os.environ PYTHON_CMD ] ; + +using gcc : 4.8.3 : $(PYTHON) $(here)/src/gcc-4.8.3-linux.py : : <target-os>linux ; +using gcc : 4.2.1 : $(PYTHON) $(here)/src/gcc-4.2.1-darwin.py : : <target-os>darwin ; + +# hard-code this to make the test work on other platforms +modules.poke darwin : .host-osx-version : 10.11.0 ; +using darwin : 4.2.1 : $(PYTHON) $(here)/src/darwin-4.2.1.py + : <archiver>$(here)/src/bin/libtool + <striper>$(here)/src/bin/strip + : <target-os>darwin + ; + +using clang-darwin : 3.9.0 : $(PYTHON) $(here)/src/clang-3.9.0-darwin.py + : <archiver>$(here)/src/bin/ar + <ranlib>$(here)/src/bin/ranlib + ; + +using clang-linux : 3.9.0 : $(PYTHON) $(here)/src/clang-linux-3.9.0.py + : <archiver>$(here)/src/bin/ar + <ranlib>$(here)/src/bin/ranlib + ; + +using clang-vxworks : 4.0.1 : $(PYTHON) $(here)/src/clang-vxworks-4.0.1.py + : <linker>$(here)/src/bin/ld + <archiver>$(here)/src/bin/ar + ; + +using intel-darwin : 10.2 : $(PYTHON) $(here)/src/intel-darwin-10.2.py + : <archiver>$(here)/src/bin/ar + <ranlib>$(here)/src/bin/ranlib + ; diff --git a/src/boost/tools/build/test/toolset-mock/src/Jamroot.jam b/src/boost/tools/build/test/toolset-mock/src/Jamroot.jam new file mode 100644 index 00000000..c8fc0078 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/Jamroot.jam @@ -0,0 +1,61 @@ +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os ; +import print ; +import regex ; +import feature ; + +.PYTHON = [ os.environ PYTHON_CMD ] ; +path-constant .AR : ar.py ; +path-constant .RANLIB : ranlib.py ; +path-constant .LIBTOOL : libtool.py ; +path-constant .STRIP : strip.py ; +path-constant .LD : ld.py ; + +rule c-escape ( str ) +{ + return [ regex.replace $(str) \\\\ \\\\ ] ; +} + +rule cfg-header ( target : : properties * ) +{ + local PYTHON = [ c-escape $(.PYTHON) ] ; + local AR = [ c-escape $(.AR) ] ; + local RANLIB = [ c-escape $(.RANLIB) ] ; + local LIBTOOL = [ c-escape $(.LIBTOOL) ] ; + local STRIP = [ c-escape $(.STRIP) ] ; + local LD = [ c-escape $(.LD) ] ; + print.output $(target) ; + print.text "#define PYTHON_CMD "\"$(PYTHON)\" : true ; + print.text "#define AR_CMD "\"$(AR)\" : true ; + print.text "#define RANLIB_CMD "\"$(RANLIB)\" : true ; + print.text "#define LIBTOOL_CMD "\"$(LIBTOOL)\" : true ; + print.text "#define STRIP_CMD "\"$(STRIP)\" : true ; + print.text "#define LD_CMD "\"$(LD)\" : true ; +} + +# We can only build one variant at a time and we need to have a fixed path +project : requirements <location>bin ; + +make config.h : : @cfg-header ; + +project : requirements <implicit-dependency>config.h ; + +rule write-target-os ( target : : properties * ) +{ + local target-os = [ feature.defaults <target-os> ] ; + print.output $(target) ; + print.text $(target-os:G=) : true ; +} + +make target-os.txt : : @write-target-os ; + +exe ar : [ obj ar.obj : mock-program.cpp : <define>PY_SCRIPT=AR_CMD ] ; +exe ranlib : [ obj ranlib.obj : mock-program.cpp : <define>PY_SCRIPT=RANLIB_CMD ] ; +exe libtool : [ obj libtool.obj : mock-program.cpp : <define>PY_SCRIPT=LIBTOOL_CMD ] ; +exe strip : [ obj strip.obj : mock-program.cpp : <define>PY_SCRIPT=STRIP_CMD ] ; +exe ld : [ obj ld.obj : mock-program.cpp : <define>PY_SCRIPT=LD_CMD ] ; diff --git a/src/boost/tools/build/test/toolset-mock/src/MockProgram.py b/src/boost/tools/build/test/toolset-mock/src/MockProgram.py new file mode 100644 index 00000000..1ada7e2a --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/MockProgram.py @@ -0,0 +1,262 @@ +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from __future__ import print_function + +import sys +import os +import re + +# Represents a sequence of arguments that must appear +# in a fixed order. +class ordered: + def __init__(self, *args): + self.args = args + def match(self, command_line, pos, outputs): + for p in self.args: + res = try_match(command_line, pos, p, outputs) + if res is None: + return + pos = res + return pos + +# Represents a sequence of arguments that can appear +# in any order. +class unordered: + def __init__(self, *args): + self.args = list(args) + def match(self, command_line, pos, outputs): + unmatched = self.args[:] + while len(unmatched) > 0: + res = try_match_one(command_line, pos, unmatched, outputs) + if res is None: + return + pos = res + return pos + +# Represents a single input file. +# If id is set, then the file must have been created +# by a prior use of output_file. +# If source is set, then the file must be that source file. +class input_file: + def __init__(self, id=None, source=None): + assert((id is None) ^ (source is None)) + self.id = id + self.source = source + def check(self, path): + if path.startswith("-"): + return + if self.id is not None: + try: + with open(path, "r") as f: + data = f.read() + if data == make_file_contents(self.id): + return True + else: + return + except: + return + elif self.source is not None: + if self.source == path: + return True + else: + return + assert(False) + def match(self, command_line, pos, outputs): + if self.check(command_line[pos]): + return pos + 1 + +# Matches an output file. +# If the full pattern is matched, The +# file will be created. +class output_file: + def __init__(self, id): + self.id = id + def match(self, command_line, pos, outputs): + if command_line[pos].startswith("-"): + return + outputs.append((command_line[pos], self.id)) + return pos + 1 + +# Matches the directory containing an input_file +class target_path(object): + def __init__(self, id): + self.tester = input_file(id=id) + def match(self, command_line, pos, outputs): + arg = command_line[pos] + if arg.startswith("-"): + return + try: + for path in os.listdir(arg): + if self.tester.check(os.path.join(arg, path)): + return pos + 1 + except: + return + +# Matches a single argument, which is composed of a prefix and a path +# for example arguments of the form -ofilename. +class arg(object): + def __init__(self, prefix, a): + # The prefix should be a string, a should be target_path or input_file. + self.prefix = prefix + self.a = a + def match(self, command_line, pos, outputs): + s = command_line[pos] + if s.startswith(self.prefix) and try_match([s[len(self.prefix):]], 0, self.a, outputs) == 1: + return pos + 1 + +# Given a file id, returns a string that will be +# written to the file to allow it to be recognized. +def make_file_contents(id): + return id + +# Matches a single pattern from a list. +# If it succeeds, the matching pattern +# is removed from the list. +# Returns the index after the end of the match +def try_match_one(command_line, pos, patterns, outputs): + for p in patterns: + tmp = outputs[:] + res = try_match(command_line, pos, p, tmp) + if res is not None: + outputs[:] = tmp + patterns.remove(p) + return res + +# returns the end of the match if any +def try_match(command_line, pos, pattern, outputs): + if pos == len(command_line): + return + elif type(pattern) is str: + if pattern == command_line[pos]: + return pos + 1 + else: + return pattern.match(command_line, pos, outputs) + +known_patterns = [] +program_name = None + +# Registers a command +# The arguments should be a sequence of: +# str, ordered, unordered, arg, input_file, output_file, target_path +# kwarg: stdout is text that will be printed on success. +def command(*args, **kwargs): + global known_patterns + global program_name + stdout = kwargs.get("stdout", None) + pattern = ordered(*args) + known_patterns += [(pattern, stdout)] + if program_name is None: + program_name = args[0] + else: + assert(program_name == args[0]) + +# Use this to filter the recognized commands, based on the properties +# passed to b2. +def allow_properties(*args): + try: + return all(a in os.environ["B2_PROPERTIES"].split(" ") for a in args) + except KeyError: + return True + +# Use this in the stdout argument of command to print the command +# for running another script. +def script(name): + return os.path.join(os.path.dirname(__file__), "bin", re.sub('\.py$', '', name)) + +def match(command_line): + for (p, stdout) in known_patterns: + outputs = [] + if try_match(command_line, 0, p, outputs) == len(command_line): + return (stdout, outputs) + +# Every mock program should call this after setting up all the commands. +def main(): + command_line = [program_name] + sys.argv[1:] + result = match(command_line) + if result is not None: + (stdout, outputs) = result + if stdout is not None: + print(stdout) + for (file,id) in outputs: + with open(file, "w") as f: + f.write(make_file_contents(id)) + exit(0) + else: + print(command_line) + exit(1) + +# file should be the name of a file in the same directory +# as this. Must be called after verify_setup +def verify_file(filename): + global known_files + if filename not in known_files: + known_files.add(filename) + srcdir = os.path.dirname(__file__) + execfile(os.path.join(srcdir, filename), {}) + +def verify_setup(): + """Override the behavior of most module components + in order to detect whether they are being used correctly.""" + global main + global allow_properties + global output_file + global input_file + global target_path + global script + global command + global verify_errors + global output_ids + global input_ids + global known_files + def allow_properties(*args): + return True + def main(): + pass + def output_file(id): + global output_ids + global verify_error + if id in output_ids: + verify_error("duplicate output_file: %s" % id) + output_ids.add(id) + def input_file(id=None, source=None): + if id is not None: + input_ids.add(id) + def target_path(id): + input_ids.add(id) + def script(filename): + verify_file(filename) + def command(*args, **kwargs): + pass + verify_errors = [] + output_ids = set() + input_ids = set() + known_files = set() + +def verify_error(message): + global verify_errors + verify_errors += [message] + +def verify_finalize(): + for id in input_ids: + if not id in output_ids: + verify_error("Input file does not exist: %s" % id) + for error in verify_errors: + print("error: %s" % error) + if len(verify_errors) != 0: + return 1 + else: + return 0 + +def verify(): + srcdir = os.path.dirname(__file__) + if srcdir == '': + srcdir = '.' + verify_setup() + for f in os.listdir(srcdir): + if re.match(r"(gcc|clang|darwin|intel)-.*\.py", f): + verify_file(f) + exit(verify_finalize()) diff --git a/src/boost/tools/build/test/toolset-mock/src/ar.py b/src/boost/tools/build/test/toolset-mock/src/ar.py new file mode 100644 index 00000000..853fe1dd --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/ar.py @@ -0,0 +1,24 @@ +#!/usr/bin/python +# +# Copyright 2017-2018 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('ar', 'rc', output_file('bin/gcc-gnu-4.8.3/debug/link-static/libl1.a'), input_file('bin/gcc-gnu-4.8.3/debug/link-static/lib.o')) +command('ar', 'rc', output_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/libl1.a'), input_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/lib.o')) +command('ar', 'rc', output_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/libl1.a'), input_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/lib.o')) +command('ar', 'rc', output_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), input_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/lib.o')) +command('ar', 'rc', output_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/libl1.a'), input_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/lib.o')) +command('ar', 'rc', output_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), input_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/lib.o')) +command('ar', 'rc', output_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/libl1.a'), input_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/lib.o')) +command('ar', 'rc', output_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), input_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/lib.o')) +command('ar', 'rc', output_file('bin/clang-linux-3.9.0/debug/link-static/libl1.a'), input_file('bin/clang-linux-3.9.0/debug/link-static/lib.o')) +command('ar', 'rc', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/libl1.a'), input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/lib.o')) +command('ar', 'rcu', output_file('bin/clang-vxworks-4.0.1/debug/link-static/libl1.a'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/lib.o')) +command('ar', 'rcu', output_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/libl1.a'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/lib.o')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/clang-3.9.0-darwin.py b/src/boost/tools/build/test/toolset-mock/src/clang-3.9.0-darwin.py new file mode 100644 index 00000000..d8c2163a --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/clang-3.9.0-darwin.py @@ -0,0 +1,49 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('clang++', '-print-prog-name=ar', stdout=script('ar.py')) +command('clang++', '-print-prog-name=ranlib', stdout=script('ranlib.py')) + +# all builds are multi-threaded for darwin +if allow_properties("variant=debug", "link=shared", "runtime-link=shared"): + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-fPIC'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', '@rpath/libl1.dylib', input_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/lib.o'), unordered('-g', '-fPIC')) + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-fPIC'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/test'), input_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/main.o'), input_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/libl1.dylib'), unordered('-g', '-fPIC')) + +if allow_properties("variant=release", "link=shared", "runtime-link=shared"): + command('clang++', '-x', 'c++', unordered('-O3', '-Wno-inline', '-Wall', '-fPIC'), '-DNDEBUG', '-c', '-o', output_file('bin/clang-darwin-3.9.0/release/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-v', '-o', output_file('bin/clang-darwin-3.9.0/release/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', '@rpath/libl1.dylib', input_file('bin/clang-darwin-3.9.0/release/target-os-darwin/lib.o'), '-fPIC') + command('clang++', '-x', 'c++', unordered('-O3', '-Wno-inline', '-Wall', '-fPIC'), '-DNDEBUG', '-c', '-o', output_file('bin/clang-darwin-3.9.0/release/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('clang++', '-v', '-o', output_file('bin/clang-darwin-3.9.0/release/target-os-darwin/test'), input_file('bin/clang-darwin-3.9.0/release/target-os-darwin/main.o'), input_file('bin/clang-darwin-3.9.0/release/target-os-darwin/libl1.dylib'), '-fPIC') + +if allow_properties("variant=debug", "link=static", "runtime-link=shared"): + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/test'), input_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/main.o'), input_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/libl1.a'), '-g') + +if allow_properties("variant=debug", "link=static", "runtime-link=static"): + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/test'), input_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), unordered('-g', '-static')) + +if allow_properties("variant=debug", "link=shared", "runtime-link=shared", "architecture=x86", "address-model=32"): + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-fPIC', '-m32'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', '@rpath/libl1.dylib', input_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/lib.o'), unordered('-g', '-march=i686', '-fPIC', '-m32')) + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-fPIC', '-m32'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/test'), input_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/main.o'), input_file('bin/clang-darwin-3.9.0/debug/x86/target-os-darwin/libl1.dylib'), unordered('-g', '-march=i686', '-fPIC', '-m32')) + +if allow_properties("variant=debug", "link=shared", "runtime-link=shared", "cxxstd=latest"): + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-std=c++1z'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', '@rpath/libl1.dylib', input_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/lib.o'), unordered('-g', '-fPIC', '-std=c++1z')) + command('clang++', '-x', 'c++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-std=c++1z'), '-c', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/test'), input_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/main.o'), input_file('bin/clang-darwin-3.9.0/debug/target-os-darwin/libl1.dylib'), unordered('-g', '-fPIC', '-std=c++1z')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/clang-linux-3.9.0.py b/src/boost/tools/build/test/toolset-mock/src/clang-linux-3.9.0.py new file mode 100644 index 00000000..242d2562 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/clang-linux-3.9.0.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('clang++', '-print-prog-name=ar', stdout=script('ar.py')) +command('clang++', '-print-prog-name=ranlib', stdout=script('ranlib.py')) + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-fPIC')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/main.o'), input_file(source='main.cpp')) + command('clang++', '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-o', output_file('bin/clang-linux-3.9.0/debug/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/main.o'), input_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-fPIC')) + +if allow_properties('variant=release', 'link=shared', 'threading=single', 'runtime-link=shared', 'strip=on'): + command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-linux-3.9.0/release/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/release/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/release/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-fPIC', '-Wl,--strip-all')) + command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-linux-3.9.0/release/main.o'), input_file(source='main.cpp')) + command('clang++', '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/release/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/release/libl1.so')), '-o', output_file('bin/clang-linux-3.9.0/release/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/release/main.o'), input_file('bin/clang-linux-3.9.0/release/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-fPIC', '-Wl,--strip-all')) + +if allow_properties('variant=debug', 'link=shared', 'threading=multi', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/threading-multi/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-lrt', '-Wl,--end-group', unordered('-g', '-pthread', '-fPIC')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/main.o'), input_file(source='main.cpp')) + command('clang++', '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so')), '-o', output_file('bin/clang-linux-3.9.0/debug/threading-multi/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/threading-multi/main.o'), input_file('bin/clang-linux-3.9.0/debug/threading-multi/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-lrt', '-Wl,--end-group', unordered('-g', '-pthread', '-fPIC')) + +if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/link-static/main.o'), input_file('bin/clang-linux-3.9.0/debug/link-static/libl1.a'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', '-g') + +if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=static'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/main.o'), input_file(source='main.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/main.o'), input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/libl1.a'), '-Wl,--end-group', unordered('-g', '-static')) + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'architecture=x86', 'address-model=32'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/lib.o'), input_file(source='lib.cpp')) + command('clang++', '-o', output_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-soname', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-march=i686', '-fPIC', '-m32')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-fPIC', '-c'), '-o', output_file('bin/clang-linux-3.9.0/debug/main.o'), input_file(source='main.cpp')) + command('clang++', '-Wl,-R', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/clang-linux-3.9.0/debug/libl1.so')), '-o', output_file('bin/clang-linux-3.9.0/debug/test'), '-Wl,--start-group', input_file('bin/clang-linux-3.9.0/debug/main.o'), input_file('bin/clang-linux-3.9.0/debug/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', unordered('-g', '-march=i686', '-fPIC', '-m32')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/clang-vxworks-4.0.1.py b/src/boost/tools/build/test/toolset-mock/src/clang-vxworks-4.0.1.py new file mode 100644 index 00000000..a1fbedb1 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/clang-vxworks-4.0.1.py @@ -0,0 +1,42 @@ +#!/usr/bin/python +# +# Copyright 2018 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('clang++', '-print-prog-name=ar', stdout=script('ar.py')) +command('clang++', '-print-prog-name=ranlib', stdout=script('ranlib.py')) + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/main.o'), input_file(source='main.cpp')) + +if allow_properties('variant=release', 'link=shared', 'threading=single', 'runtime-link=shared', 'strip=on'): + command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/release/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O3', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/release/main.o'), input_file(source='main.cpp')) + +if allow_properties('variant=debug', 'link=shared', 'threading=multi', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/threading-multi/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-fPIC', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/threading-multi/main.o'), input_file(source='main.cpp')) + +if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=shared'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/link-static/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/link-static/main.o'), input_file(source='main.cpp')) + +if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=static'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/main.o'), input_file(source='main.cpp')) + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'architecture=x86', 'address-model=32'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-fPIC', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-Wall', '-g', '-march=i686', '-m32', '-fPIC', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/main.o'), input_file(source='main.cpp')) + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'rtti=off', 'exception-handling=off'): + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-fno-rtti', '-fno-exceptions', '-Wall', '-g', '-fPIC', '-D_NO_RTTI', '-D_NO_EX=1', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/lib.o'), input_file(source='lib.cpp')) + command('clang++', unordered(ordered('-x', 'c++'), '-O0', '-fno-inline', '-fno-rtti', '-fno-exceptions', '-Wall', '-g', '-fPIC', '-D_NO_RTTI', '-D_NO_EX=1', '-c'), '-o', output_file('bin/clang-vxworks-4.0.1/debug/main.o'), input_file(source='main.cpp')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/darwin-4.2.1.py b/src/boost/tools/build/test/toolset-mock/src/darwin-4.2.1.py new file mode 100644 index 00000000..d81359ca --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/darwin-4.2.1.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +script("libtool.py") + +command('g++', '-dumpversion', stdout='4.2.1') + +# all builds are multi-threaded for darwin +if allow_properties("variant=debug", "link=shared", "runtime-link=shared"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-dynamic', '-gdwarf-2', '-fexceptions', '-fPIC'), '-c', '-o', output_file('bin/darwin-4.2.1/debug/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', '-dynamiclib', '-Wl,-single_module', '-install_name', 'libl1.dylib', '-o', output_file('bin/darwin-4.2.1/debug/target-os-darwin/libl1.dylib'), input_file('bin/darwin-4.2.1/debug/target-os-darwin/lib.o'), '-headerpad_max_install_names', unordered('-g', '-fPIC')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-dynamic', '-gdwarf-2', '-fexceptions', '-fPIC'), '-c', '-o', output_file('bin/darwin-4.2.1/debug/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/darwin-4.2.1/debug/target-os-darwin/test'), input_file('bin/darwin-4.2.1/debug/target-os-darwin/main.o'), input_file('bin/darwin-4.2.1/debug/target-os-darwin/libl1.dylib'), unordered('-g', '-fPIC')) + +if allow_properties("variant=release", "link=shared", "runtime-link=shared"): + command('g++', unordered('-O3', '-Wno-inline', '-Wall', '-dynamic', '-gdwarf-2', '-fexceptions', '-fPIC'), '-DNDEBUG', '-c', '-o', output_file('bin/darwin-4.2.1/release/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', '-dynamiclib', '-Wl,-single_module', '-install_name', 'libl1.dylib', '-o', output_file('bin/darwin-4.2.1/release/target-os-darwin/libl1.dylib'), input_file('bin/darwin-4.2.1/release/target-os-darwin/lib.o'), '-headerpad_max_install_names', unordered(ordered('-Wl,-dead_strip', '-no_dead_strip_inits_and_terms'), '-fPIC')) + command('g++', unordered('-O3', '-Wno-inline', '-Wall', '-dynamic', '-gdwarf-2', '-fexceptions', '-fPIC'), '-DNDEBUG', '-c', '-o', output_file('bin/darwin-4.2.1/release/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/darwin-4.2.1/release/target-os-darwin/test'), input_file('bin/darwin-4.2.1/release/target-os-darwin/main.o'), input_file('bin/darwin-4.2.1/release/target-os-darwin/libl1.dylib'), unordered(ordered('-Wl,-dead_strip', '-no_dead_strip_inits_and_terms'), '-fPIC')) + +if allow_properties("variant=debug", "link=static", "runtime-link=shared"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-gdwarf-2', '-fexceptions'), '-c', '-o', output_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-gdwarf-2', '-fexceptions'), '-c', '-o', output_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/test'), input_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/main.o'), input_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/libl1.a'), '-g') + +if allow_properties("variant=debug", "link=static", "runtime-link=static"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-gdwarf-2', '-fexceptions'), '-c', '-o', output_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-gdwarf-2', '-fexceptions'), '-c', '-o', output_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/test'), input_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), unordered('-g', ordered('-nodefaultlibs', '-shared-libgcc', '-lstdc++-static', '-lgcc_eh', '-lgcc', '-lSystem'), '-static')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/gcc-4.2.1-darwin.py b/src/boost/tools/build/test/toolset-mock/src/gcc-4.2.1-darwin.py new file mode 100644 index 00000000..76058c32 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/gcc-4.2.1-darwin.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('g++', '-print-prog-name=ar', stdout=script('ar.py')) +command('g++', '-print-prog-name=ranlib', stdout=script('ranlib.py')) + +# all builds are multi-threaded for darwin +if allow_properties("variant=debug", "link=shared", "runtime-link=shared"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-fPIC'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', '-o', output_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/libl1.dylib'), '-shared', input_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/lib.o'), unordered('-g', '-fPIC')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-fPIC'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-Wl,-rpath', arg('-Wl,', target_path('bin/gcc-darwin-4.2.1/debug/target-os-darwin/libl1.dylib')), '-o', output_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/test'), input_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/main.o'), input_file('bin/gcc-darwin-4.2.1/debug/target-os-darwin/libl1.dylib'), unordered('-g', '-fPIC')) + +if allow_properties("variant=release", "link=shared", "runtime-link=shared"): + command('g++', unordered('-O3', '-finline-functions', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', '-o', output_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/libl1.dylib'), '-shared', input_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/lib.o'), '-fPIC') + command('g++', unordered('-O3', '-finline-functions', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-Wl,-rpath', arg('-Wl,', target_path('bin/gcc-darwin-4.2.1/release/target-os-darwin/libl1.dylib')), '-o', output_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/test'), input_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/main.o'), input_file('bin/gcc-darwin-4.2.1/release/target-os-darwin/libl1.dylib'), '-fPIC') + +if allow_properties("variant=debug", "link=static", "runtime-link=shared"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/test'), input_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/main.o'), input_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/libl1.a'), '-g') + +if allow_properties("variant=debug", "link=static", "runtime-link=static"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/test'), input_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), unordered('-g', '-static')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/gcc-4.8.3-linux.py b/src/boost/tools/build/test/toolset-mock/src/gcc-4.8.3-linux.py new file mode 100644 index 00000000..5604ee5d --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/gcc-4.8.3-linux.py @@ -0,0 +1,50 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('g++', '-print-prog-name=ar', stdout=script('ar.py')) +command('g++', '-print-prog-name=ranlib', stdout=script('ranlib.py')) + +if allow_properties("variant=debug", "link=shared", "threading=single", "runtime-link=shared"): + command("g++", unordered("-O0", "-fno-inline", "-Wall", "-g", "-fPIC"), "-c", "-o", output_file("bin/gcc-gnu-4.8.3/debug/lib.o"), input_file(source="lib.cpp")) + command("g++", "-o", output_file("bin/gcc-gnu-4.8.3/debug/libl1.so"), "-Wl,-h", "-Wl,libl1.so", "-shared", "-Wl,--start-group", input_file("bin/gcc-gnu-4.8.3/debug/lib.o"), "-Wl,-Bstatic", "-Wl,-Bdynamic", "-Wl,--end-group", unordered("-g", "-fPIC")) + command("g++", unordered("-O0", "-fno-inline", "-Wall", "-g", "-fPIC"), "-c", "-o", output_file("bin/gcc-gnu-4.8.3/debug/main.o"), input_file(source="main.cpp")) + command("g++", "-Wl,-rpath", arg("-Wl,", target_path("bin/gcc-gnu-4.8.3/debug/libl1.so")), "-Wl,-rpath-link", arg("-Wl,", target_path("bin/gcc-gnu-4.8.3/debug/libl1.so")), "-o", output_file("bin/gcc-gnu-4.8.3/debug/test"), "-Wl,--start-group", input_file("bin/gcc-gnu-4.8.3/debug/main.o"), input_file("bin/gcc-gnu-4.8.3/debug/libl1.so"), "-Wl,-Bstatic", "-Wl,-Bdynamic", "-Wl,--end-group", unordered("-g", "-fPIC")) + +if allow_properties("variant=release", "link=shared", "threading=single", "runtime-link=shared"): + command('g++', unordered('-O3', '-finline-functions', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG'), '-c', '-o', output_file('bin/gcc-gnu-4.8.3/release/lib.o'), input_file(source='lib.cpp')) + command('g++', '-o', output_file('bin/gcc-gnu-4.8.3/release/libl1.so'), '-Wl,-h', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/gcc-gnu-4.8.3/release/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', '-fPIC') + command('g++', unordered('-O3', '-finline-functions', '-Wno-inline', '-Wall', '-fPIC', '-DNDEBUG'), '-c', '-o', output_file('bin/gcc-gnu-4.8.3/release/main.o'), input_file(source='main.cpp')) + command('g++', '-Wl,-rpath', arg('-Wl,', target_path('bin/gcc-gnu-4.8.3/release/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/gcc-gnu-4.8.3/release/libl1.so')), '-o', output_file('bin/gcc-gnu-4.8.3/release/test'), '-Wl,--start-group', input_file('bin/gcc-gnu-4.8.3/release/main.o'), input_file('bin/gcc-gnu-4.8.3/release/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', '-fPIC') + +if allow_properties("variant=debug", "link=shared", "threading=multi", "runtime-link=shared"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-fPIC'), '-c', '-o', output_file('bin/gcc-gnu-4.8.3/debug/threading-multi/lib.o'), input_file(source='lib.cpp')) + command('g++', '-o', output_file('bin/gcc-gnu-4.8.3/debug/threading-multi/libl1.so'), '-Wl,-h', '-Wl,libl1.so', '-shared', '-Wl,--start-group', input_file('bin/gcc-gnu-4.8.3/debug/threading-multi/lib.o'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-lrt', '-Wl,--end-group', unordered('-g', '-pthread', '-fPIC')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-pthread', '-fPIC'), '-c', '-o', output_file('bin/gcc-gnu-4.8.3/debug/threading-multi/main.o'), input_file(source='main.cpp')) + command('g++', '-Wl,-rpath', arg('-Wl,', target_path('bin/gcc-gnu-4.8.3/debug/threading-multi/libl1.so')), '-Wl,-rpath-link', arg('-Wl,', target_path('bin/gcc-gnu-4.8.3/debug/threading-multi/libl1.so')), '-o', output_file('bin/gcc-gnu-4.8.3/debug/threading-multi/test'), '-Wl,--start-group', input_file('bin/gcc-gnu-4.8.3/debug/threading-multi/main.o'), input_file('bin/gcc-gnu-4.8.3/debug/threading-multi/libl1.so'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-lrt', '-Wl,--end-group', unordered('-g', '-pthread', '-fPIC')) + +if allow_properties("variant=debug", "link=static", "threading=single", "runtime-link=shared"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/gcc-gnu-4.8.3/debug/link-static/lib.o'), input_file(source='lib.cpp')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g'), '-c', '-o', output_file('bin/gcc-gnu-4.8.3/debug/link-static/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/gcc-gnu-4.8.3/debug/link-static/test'), '-Wl,--start-group', input_file('bin/gcc-gnu-4.8.3/debug/link-static/main.o'), input_file('bin/gcc-gnu-4.8.3/debug/link-static/libl1.a'), '-Wl,-Bstatic', '-Wl,-Bdynamic', '-Wl,--end-group', '-g') + +if allow_properties("variant=debug", "link=static", "threading=single", "runtime-link=static"): + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/lib.o'), input_file(source='lib.cpp')) + command('g++', unordered('-O0', '-fno-inline', '-Wall', '-g', '-c'), '-o', output_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/main.o'), input_file(source='main.cpp')) + command('g++', '-o', output_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/test'), '-Wl,--start-group', input_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/main.o'), input_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/libl1.a'), '-Wl,--end-group', unordered('-g', '-static')) + + +if allow_properties("variant=debug", "link=shared", "threading=single", "runtime-link=shared"): + command("g++", unordered("-O0", "-fno-inline", "-Wall", "-g", "-fPIC", "-std=c++1y"), "-c", "-o", output_file("bin/gcc-gnu-4.8.3/debug/lib.o"), input_file(source="lib.cpp")) + command("g++", "-o", output_file("bin/gcc-gnu-4.8.3/debug/libl1.so"), "-Wl,-h", "-Wl,libl1.so", "-shared", "-Wl,--start-group", input_file("bin/gcc-gnu-4.8.3/debug/lib.o"), "-Wl,-Bstatic", "-Wl,-Bdynamic", "-Wl,--end-group", unordered("-g", "-fPIC", "-std=c++1y")) + command("g++", unordered("-O0", "-fno-inline", "-Wall", "-g", "-fPIC", "-std=c++1y"), "-c", "-o", output_file("bin/gcc-gnu-4.8.3/debug/main.o"), input_file(source="main.cpp")) + command("g++", "-Wl,-rpath", arg("-Wl,", target_path("bin/gcc-gnu-4.8.3/debug/libl1.so")), "-Wl,-rpath-link", arg("-Wl,", target_path("bin/gcc-gnu-4.8.3/debug/libl1.so")), "-o", output_file("bin/gcc-gnu-4.8.3/debug/test"), "-Wl,--start-group", input_file("bin/gcc-gnu-4.8.3/debug/main.o"), input_file("bin/gcc-gnu-4.8.3/debug/libl1.so"), "-Wl,-Bstatic", "-Wl,-Bdynamic", "-Wl,--end-group", unordered("-g", "-fPIC", "-std=c++1y")) + + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/intel-darwin-10.2.py b/src/boost/tools/build/test/toolset-mock/src/intel-darwin-10.2.py new file mode 100644 index 00000000..314d6c45 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/intel-darwin-10.2.py @@ -0,0 +1,43 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('icc', '-print-prog-name=ar', stdout=script('ar.py')) +command('icc', '-print-prog-name=ranlib', stdout=script('ranlib.py')) + +# all builds are multi-threaded for darwin +if allow_properties("variant=debug", "link=shared", "runtime-link=shared"): + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0', '-fPIC'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/debug/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', 'libl1.dylib', input_file('bin/intel-darwin-10.2/debug/target-os-darwin/lib.o'), unordered('-g', ordered('-shared-intel', '-lstdc++', '-lpthread'), '-fPIC')) + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0', '-fPIC'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/debug/target-os-darwin/test'), input_file('bin/intel-darwin-10.2/debug/target-os-darwin/main.o'), input_file('bin/intel-darwin-10.2/debug/target-os-darwin/libl1.dylib'), unordered('-g', ordered('-shared-intel', '-lstdc++', '-lpthread'), '-fPIC')) + +if allow_properties("variant=release", "link=shared", "runtime-link=shared"): + command('icc', '-xc++', unordered('-O3', '-inline-level=2', '-w1', '-vec-report0', '-fPIC'), '-DNDEBUG', '-c', '-o', output_file('bin/intel-darwin-10.2/release/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/release/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', 'libl1.dylib', input_file('bin/intel-darwin-10.2/release/target-os-darwin/lib.o'), unordered(ordered('-shared-intel', '-lstdc++', '-lpthread'), '-fPIC')) + command('icc', '-xc++', unordered('-O3', '-inline-level=2', '-w1', '-vec-report0', '-fPIC'), '-DNDEBUG', '-c', '-o', output_file('bin/intel-darwin-10.2/release/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/release/target-os-darwin/test'), input_file('bin/intel-darwin-10.2/release/target-os-darwin/main.o'), input_file('bin/intel-darwin-10.2/release/target-os-darwin/libl1.dylib'), unordered(ordered('-shared-intel', '-lstdc++', '-lpthread'), '-fPIC')) + +if allow_properties("variant=debug", "link=static", "runtime-link=shared"): + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/test'), input_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/main.o'), input_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/libl1.a'), '-g', ordered('-shared-intel', '-lstdc++', '-lpthread')) + +if allow_properties("variant=debug", "link=static", "runtime-link=static"): + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/test'), input_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/main.o'), input_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), unordered('-g', ordered('-static', '-static-intel', '-lstdc++', '-lpthread'), '-static')) + +if allow_properties("variant=debug", "link=shared", "runtime-link=shared", "architecture=x86", "address-model=32"): + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0', '-march=i686', '-fPIC', '-m32'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/lib.o'), input_file(source='lib.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/libl1.dylib'), '-single_module', '-dynamiclib', '-install_name', 'libl1.dylib', input_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/lib.o'), unordered('-g', ordered('-shared-intel', '-lstdc++', '-lpthread'), '-march=i686', '-fPIC', '-m32')) + command('icc', '-xc++', unordered('-O0', '-inline-level=0', '-w1', '-g', '-vec-report0', '-march=i686', '-fPIC', '-m32'), '-c', '-o', output_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/main.o'), input_file(source='main.cpp')) + command('icc', '-o', output_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/test'), input_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/main.o'), input_file('bin/intel-darwin-10.2/debug/x86/target-os-darwin/libl1.dylib'), unordered('-g', ordered('-shared-intel', '-lstdc++', '-lpthread'), '-march=i686', '-fPIC', '-m32')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/ld.py b/src/boost/tools/build/test/toolset-mock/src/ld.py new file mode 100644 index 00000000..2b644e50 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/ld.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +# +# Copyright 2018 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared'): + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/libl1.so'), input_file('bin/clang-vxworks-4.0.1/debug/lib.o'), unordered('-g', '-fPIC'), '-fpic', '-shared', '-non-static') + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/test'), input_file('bin/clang-vxworks-4.0.1/debug/main.o'), input_file('bin/clang-vxworks-4.0.1/debug/libl1.so'), unordered('-g', '-fPIC')) + +if allow_properties('variant=release', 'link=shared', 'threading=single', 'runtime-link=shared', 'strip=on'): + command('ld', '-t', '-o', output_file('bin/clang-vxworks-4.0.1/release/libl1.so'), input_file('bin/clang-vxworks-4.0.1/release/lib.o'), unordered('-fPIC', '-Wl,--strip-all'), '-fpic', '-shared', '-non-static') + command('ld', '-t', '-o', output_file('bin/clang-vxworks-4.0.1/release/test'), input_file('bin/clang-vxworks-4.0.1/release/main.o'), input_file('bin/clang-vxworks-4.0.1/release/libl1.so'), unordered('-fPIC', '-Wl,--strip-all')) + +if allow_properties('variant=debug', 'link=shared', 'threading=multi', 'runtime-link=shared'): + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/threading-multi/libl1.so'), input_file('bin/clang-vxworks-4.0.1/debug/threading-multi/lib.o'), unordered('-g', '-fPIC'), '-fpic', '-shared', '-non-static') + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/threading-multi/test'), input_file('bin/clang-vxworks-4.0.1/debug/threading-multi/main.o'), input_file('bin/clang-vxworks-4.0.1/debug/threading-multi/libl1.so'), unordered('-g', '-fPIC')) + +if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=shared'): + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/link-static/test'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/main.o'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/libl1.a'), '-g') + +if allow_properties('variant=debug', 'link=static', 'threading=single', 'runtime-link=static'): + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/test'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/main.o'), input_file('bin/clang-vxworks-4.0.1/debug/link-static/runtime-link-static/libl1.a'), unordered('-g')) + +if allow_properties('variant=debug', 'link=shared', 'threading=single', 'runtime-link=shared', 'architecture=x86', 'address-model=32'): + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/libl1.so'), input_file('bin/clang-vxworks-4.0.1/debug/lib.o'), unordered('-g', '-march=i686', '-fPIC', '-m32'), '-fpic', '-shared', '-non-static') + command('ld', '-o', output_file('bin/clang-vxworks-4.0.1/debug/test'), input_file('bin/clang-vxworks-4.0.1/debug/main.o'), input_file('bin/clang-vxworks-4.0.1/debug/libl1.so'), unordered('-g', '-march=i686', '-fPIC', '-m32')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/libtool.py b/src/boost/tools/build/test/toolset-mock/src/libtool.py new file mode 100644 index 00000000..9f58dc96 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/libtool.py @@ -0,0 +1,14 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('libtool', '-static', '-o', output_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/libl1.a'), input_file('bin/darwin-4.2.1/debug/link-static/target-os-darwin/lib.o')) +command('libtool', '-static', '-o', output_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/libl1.a'), input_file('bin/darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/lib.o')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/mock-program.cpp b/src/boost/tools/build/test/toolset-mock/src/mock-program.cpp new file mode 100644 index 00000000..62dd4b8a --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/mock-program.cpp @@ -0,0 +1,42 @@ +// mock-program.cpp +// +// Copyright (c) 2017 Steven Watanabe +// +// Distributed under the Boost Software License Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This program does nothing except to exec a python script + +#include <vector> +#include <iostream> +#include <stdio.h> +#include "config.h" + +#if defined(_WIN32) + #include <process.h> + #define execv _execv +#else + #include <unistd.h> +#endif + +#ifndef PY_SCRIPT +#error PY_SCRIPT must be defined to the absolute path to the script to run +#endif + +#ifndef PYTHON_CMD +#error PYTHON_CMD must be defined to the absolute path to the python interpreter +#endif + +int main(int argc, char ** argv) +{ + std::vector<char *> args; + char python_cmd[] = PYTHON_CMD; + char script[] = PY_SCRIPT; + args.push_back(python_cmd); + args.push_back(script); + args.insert(args.end(), argv + 1, argv + argc); + args.push_back(NULL); + execv(python_cmd, &args[0]); + perror("exec"); +} diff --git a/src/boost/tools/build/test/toolset-mock/src/project-config.jam b/src/boost/tools/build/test/toolset-mock/src/project-config.jam new file mode 100644 index 00000000..73dcf42d --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/project-config.jam @@ -0,0 +1,5 @@ +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/boost/tools/build/test/toolset-mock/src/ranlib.py b/src/boost/tools/build/test/toolset-mock/src/ranlib.py new file mode 100644 index 00000000..4abe21ed --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/ranlib.py @@ -0,0 +1,22 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('ranlib', input_file('bin/gcc-gnu-4.8.3/debug/link-static/libl1.a')) +command('ranlib', input_file('bin/gcc-gnu-4.8.3/debug/link-static/runtime-link-static/libl1.a')) +command('ranlib', input_file('bin/gcc-darwin-4.2.1/debug/link-static/target-os-darwin/libl1.a')) +command('ranlib', input_file('bin/gcc-darwin-4.2.1/debug/link-static/runtime-link-static/target-os-darwin/libl1.a')) +command('ranlib', input_file('bin/clang-darwin-3.9.0/debug/link-static/target-os-darwin/libl1.a')) +command('ranlib', input_file('bin/clang-darwin-3.9.0/debug/link-static/runtime-link-static/target-os-darwin/libl1.a')) +command('ranlib', '-cs', input_file('bin/intel-darwin-10.2/debug/link-static/target-os-darwin/libl1.a')) +command('ranlib', '-cs', input_file('bin/intel-darwin-10.2/debug/link-static/runtime-link-static/target-os-darwin/libl1.a')) +command('ranlib', input_file('bin/clang-linux-3.9.0/debug/link-static/libl1.a')) +command('ranlib', input_file('bin/clang-linux-3.9.0/debug/link-static/runtime-link-static/libl1.a')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/strip.py b/src/boost/tools/build/test/toolset-mock/src/strip.py new file mode 100644 index 00000000..6245588b --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/strip.py @@ -0,0 +1,13 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +command('strip', '-S', '-x', input_file('bin/darwin-4.2.1/release/target-os-darwin/test')) + +main() diff --git a/src/boost/tools/build/test/toolset-mock/src/verify.py b/src/boost/tools/build/test/toolset-mock/src/verify.py new file mode 100644 index 00000000..6e5e0ea7 --- /dev/null +++ b/src/boost/tools/build/test/toolset-mock/src/verify.py @@ -0,0 +1,9 @@ +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +from MockProgram import * + +verify() diff --git a/src/boost/tools/build/test/toolset_clang_darwin.py b/src/boost/tools/build/test/toolset_clang_darwin.py new file mode 100644 index 00000000..53c7c07c --- /dev/null +++ b/src/boost/tools/build/test/toolset_clang_darwin.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates the clang-darwin toolset using a mock of clang + +from TestToolset import test_toolset + +test_toolset("clang-darwin", "3.9.0", [ + ["target-os=darwin"], + ["target-os=darwin", "release", "strip=on", "linkflags=-v"], + ["target-os=darwin", "threading=multi"], + ["target-os=darwin", "link=static"], + ["target-os=darwin", "link=static", "runtime-link=static"], + ["target-os=darwin", "architecture=x86", "address-model=32"], + ["target-os=darwin", "cxxstd=latest"]]) diff --git a/src/boost/tools/build/test/toolset_clang_linux.py b/src/boost/tools/build/test/toolset_clang_linux.py new file mode 100644 index 00000000..2fbf84b6 --- /dev/null +++ b/src/boost/tools/build/test/toolset_clang_linux.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates the clang_linux toolset using a mock of clang + +from TestToolset import test_toolset + +test_toolset("clang-linux", "3.9.0", [ + ["target-os=linux"], + ["target-os=linux", "release", "strip=on"], + ["target-os=linux", "threading=multi"], + ["target-os=linux", "link=static"], + ["target-os=linux", "link=static", "runtime-link=static"], + ["target-os=linux", "architecture=x86", "address-model=32"]]) diff --git a/src/boost/tools/build/test/toolset_clang_vxworks.py b/src/boost/tools/build/test/toolset_clang_vxworks.py new file mode 100644 index 00000000..efdc1275 --- /dev/null +++ b/src/boost/tools/build/test/toolset_clang_vxworks.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# +# Copyright 2018 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates the clang_vxworks toolset using a mock of clang + +from TestToolset import test_toolset + +test_toolset("clang-vxworks", "4.0.1", [ + ["target-os=vxworks"], + ["target-os=vxworks", "release", "strip=on", "linkflags=-t"], + ["target-os=vxworks", "threading=multi"], + ["target-os=vxworks", "link=static"], + ["target-os=vxworks", "link=static", "runtime-link=static"], + ["target-os=vxworks", "architecture=x86", "address-model=32"], + ["target-os=vxworks", "rtti=off", "exception-handling=off"]]) diff --git a/src/boost/tools/build/test/toolset_darwin.py b/src/boost/tools/build/test/toolset_darwin.py new file mode 100644 index 00000000..58ecc8d2 --- /dev/null +++ b/src/boost/tools/build/test/toolset_darwin.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates the darwin toolset using a mock of gcc + +from TestToolset import test_toolset + +test_toolset("darwin", "4.2.1", [ + ["target-os=darwin"], + ["target-os=darwin", "release", "strip=on"], + ["target-os=darwin", "threading=multi"], + ["target-os=darwin", "link=static"], + ["target-os=darwin", "link=static", "runtime-link=static"], +# Address-model handling is quite broken +# ["target-os=darwin", "architecture=x86", "address-model=32"] +]) diff --git a/src/boost/tools/build/test/toolset_defaults.py b/src/boost/tools/build/test/toolset_defaults.py new file mode 100644 index 00000000..6d76c10f --- /dev/null +++ b/src/boost/tools/build/test/toolset_defaults.py @@ -0,0 +1,60 @@ +#!/usr/bin/python + +# Copyright 2018 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the handling of toolset.add-defaults + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0, ignore_toolset_requirements=False) + +t.write('jamroot.jam', ''' +import toolset ; +import errors ; +import feature : feature ; +import set ; + +feature f1 : a b ; +feature f2 : c d ; +feature f3 : e f ; +feature f4 : g h ; +feature f5 : i j ; +feature f6 : k l m ; + +rule test-rule ( properties * ) +{ + if <f1>a in $(properties) + { + return <f2>d ; + } +} + +toolset.add-defaults + <conditional>@test-rule + <f3>e:<f4>h + <f5>i:<f6>l +; + +rule check-requirements ( target : sources * : properties * ) +{ + local expected = <f2>d <f4>h <f6>m ; + local unexpected = <f2>c <f4>g <f6>k <f6>l ; + local missing = [ set.difference $(expected) : $(properties) ] ; + if $(missing) + { + errors.error $(missing) not present ; + } + local extra = [ set.intersection $(unexpected) : $(properties) ] ; + if $(extra) + { + errors.error $(extra) present ; + } +} +make test : : @check-requirements : <f6>m ; +''') + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/toolset_gcc.py b/src/boost/tools/build/test/toolset_gcc.py new file mode 100644 index 00000000..d3d65fcf --- /dev/null +++ b/src/boost/tools/build/test/toolset_gcc.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates the gcc toolset using a mock of gcc + +from TestToolset import test_toolset + +test_toolset("gcc", "4.8.3", [ + ["target-os=linux"], + ["target-os=linux", "release"], + ["target-os=linux", "threading=multi"], + ["target-os=linux", "link=static"], + ["target-os=linux", "link=static", "runtime-link=static"], + ["target-os=linux", "cxxstd=latest"]]) + +test_toolset("gcc", "4.2.1", [ + ["target-os=darwin"], + ["target-os=darwin", "release"], + ["target-os=darwin", "threading=multi"], + ["target-os=darwin", "link=static"], + ["target-os=darwin", "link=static", "runtime-link=static"]]) diff --git a/src/boost/tools/build/test/toolset_intel_darwin.py b/src/boost/tools/build/test/toolset_intel_darwin.py new file mode 100644 index 00000000..db044490 --- /dev/null +++ b/src/boost/tools/build/test/toolset_intel_darwin.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +# +# Copyright 2017 Steven Watanabe +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# validates the intel-darwin toolset using a mock of icc + +from TestToolset import test_toolset + +test_toolset("intel-darwin", "10.2", [ + ["target-os=darwin"], + ["target-os=darwin", "release", "strip=on"], + ["target-os=darwin", "threading=multi"], + ["target-os=darwin", "link=static"], + ["target-os=darwin", "link=static", "runtime-link=static"], + ["target-os=darwin", "architecture=x86", "address-model=32"]]) diff --git a/src/boost/tools/build/test/toolset_requirements.py b/src/boost/tools/build/test/toolset_requirements.py new file mode 100644 index 00000000..c9a8fa8e --- /dev/null +++ b/src/boost/tools/build/test/toolset_requirements.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +# Copyright 2014 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the handling of toolset.add-requirements + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0, ignore_toolset_requirements=False) + +t.write('jamroot.jam', ''' +import toolset ; +import errors ; + +rule test-rule ( properties * ) +{ + return <define>TEST_INDIRECT_CONDITIONAL ; +} + +toolset.add-requirements + <define>TEST_MACRO + <conditional>@test-rule + <link>shared:<define>TEST_CONDITIONAL +; + +rule check-requirements ( target : sources * : properties * ) +{ + local macros = TEST_MACRO TEST_CONDITIONAL TEST_INDIRECT_CONDITIONAL ; + for local m in $(macros) + { + if ! <define>$(m) in $(properties) + { + errors.error $(m) not defined ; + } + } +} +make test : : @check-requirements ; +''') + +t.run_build_system() + +t.cleanup() diff --git a/src/boost/tools/build/test/tree.py b/src/boost/tools/build/test/tree.py new file mode 100644 index 00000000..11899dd7 --- /dev/null +++ b/src/boost/tools/build/test/tree.py @@ -0,0 +1,245 @@ +# Copyright 2003 Dave Abrahams +# Copyright 2001, 2002 Vladimir Prus +# Copyright 2012 Jurko Gospodnetic +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +############################################################################### +# +# Based in part on an old Subversion tree.py source file (tools for comparing +# directory trees). See http://subversion.tigris.org for more information. +# +# Copyright (c) 2001 Sam Tobin-Hochstadt. All rights reserved. +# +# This software is licensed as described in the file COPYING, which you should +# have received as part of this distribution. The terms are also available at +# http://subversion.tigris.org/license-1.html. If newer versions of this +# license are posted there, you may use a newer version instead, at your +# option. +# +############################################################################### + +from __future__ import print_function + +import os +import os.path +import stat +import sys + + +class TreeNode: + """ + Fundamental data type used to build file system tree structures. + + If CHILDREN is None, then the node represents a file. Otherwise, CHILDREN + is a list of the nodes representing that directory's children. + + NAME is simply the name of the file or directory. CONTENTS is a string + holding the file's contents (if a file). + + """ + + def __init__(self, name, children=None, contents=None): + assert children is None or contents is None + self.name = name + self.mtime = 0 + self.children = children + self.contents = contents + self.path = name + + def add_child(self, newchild): + assert not self.is_file() + for a in self.children: + if a.name == newchild.name: + if newchild.is_file(): + a.contents = newchild.contents + a.path = os.path.join(self.path, newchild.name) + else: + for i in newchild.children: + a.add_child(i) + break + else: + self.children.append(newchild) + newchild.path = os.path.join(self.path, newchild.name) + + def get_child(self, name): + """ + If the given TreeNode directory NODE contains a child named NAME, + return the child; else, return None. + + """ + for n in self.children: + if n.name == name: + return n + + def is_file(self): + return self.children is None + + def pprint(self): + print(" * Node name: %s" % self.name) + print(" Path: %s" % self.path) + print(" Contents: %s" % self.contents) + if self.is_file(): + print(" Children: is a file.") + else: + print(" Children: %d" % len(self.children)) + + +class TreeDifference: + def __init__(self): + self.added_files = [] + self.removed_files = [] + self.modified_files = [] + self.touched_files = [] + + def append(self, other): + self.added_files.extend(other.added_files) + self.removed_files.extend(other.removed_files) + self.modified_files.extend(other.modified_files) + self.touched_files.extend(other.touched_files) + + def ignore_directories(self): + """Removes directories from our lists of found differences.""" + not_dir = lambda x : x[-1] != "/" + self.added_files = list(filter(not_dir, self.added_files)) + self.removed_files = list(filter(not_dir, self.removed_files)) + self.modified_files = list(filter(not_dir, self.modified_files)) + self.touched_files = list(filter(not_dir, self.touched_files)) + + def pprint(self, file=sys.stdout): + file.write("Added files : %s\n" % self.added_files) + file.write("Removed files : %s\n" % self.removed_files) + file.write("Modified files: %s\n" % self.modified_files) + file.write("Touched files : %s\n" % self.touched_files) + + def empty(self): + return not (self.added_files or self.removed_files or + self.modified_files or self.touched_files) + + +def build_tree(path): + """ + Takes PATH as the folder path, walks the file system below that path, and + creates a tree structure based on any files and folders found there. + Returns the prepared tree structure plus the maximum file modification + timestamp under the given folder. + + """ + return _handle_dir(os.path.normpath(path)) + + +def tree_difference(a, b): + """Compare TreeNodes A and B, and create a TreeDifference instance.""" + return _do_tree_difference(a, b, "", True) + + +def _do_tree_difference(a, b, parent_path, root=False): + """Internal recursive worker function for tree_difference().""" + + # We do not want to list root node names. + if root: + assert not parent_path + assert not a.is_file() + assert not b.is_file() + full_path = "" + else: + assert a.name == b.name + full_path = parent_path + a.name + result = TreeDifference() + + # A and B are both files. + if a.is_file() and b.is_file(): + if a.contents != b.contents: + result.modified_files.append(full_path) + elif a.mtime != b.mtime: + result.touched_files.append(full_path) + return result + + # Directory converted to file. + if not a.is_file() and b.is_file(): + result.removed_files.extend(_traverse_tree(a, parent_path)) + result.added_files.append(full_path) + + # File converted to directory. + elif a.is_file() and not b.is_file(): + result.removed_files.append(full_path) + result.added_files.extend(_traverse_tree(b, parent_path)) + + # A and B are both directories. + else: + if full_path: + full_path += "/" + accounted_for = [] # Children present in both trees. + for a_child in a.children: + b_child = b.get_child(a_child.name) + if b_child: + accounted_for.append(b_child) + result.append(_do_tree_difference(a_child, b_child, full_path)) + else: + result.removed_files.append(full_path + a_child.name) + for b_child in b.children: + if b_child not in accounted_for: + result.added_files.extend(_traverse_tree(b_child, full_path)) + + return result + + +def _traverse_tree(t, parent_path): + """Returns a list of all names in a tree.""" + assert not parent_path or parent_path[-1] == "/" + full_node_name = parent_path + t.name + if t.is_file(): + result = [full_node_name] + else: + name_prefix = full_node_name + "/" + result = [name_prefix] + for i in t.children: + result.extend(_traverse_tree(i, name_prefix)) + return result + + +def _get_text(path): + """Return a string with the textual contents of a file at PATH.""" + fp = open(path, 'rb') + try: + return fp.read() + finally: + fp.close() + + +def _handle_dir(path): + """ + Main recursive worker function for build_tree(). Returns a newly created + tree node representing the given normalized folder path as well as the + maximum file/folder modification time detected under the same path. + + """ + files = [] + dirs = [] + node = TreeNode(os.path.basename(path), children=[]) + max_mtime = node.mtime = os.stat(path).st_mtime + + # List files & folders. + for f in os.listdir(path): + f = os.path.join(path, f) + if os.path.isdir(f): + dirs.append(f) + elif os.path.isfile(f): + files.append(f) + + # Add a child node for each file. + for f in files: + fcontents = _get_text(f) + new_file_node = TreeNode(os.path.basename(f), contents=fcontents) + new_file_node.mtime = os.stat(f).st_mtime + max_mtime = max(max_mtime, new_file_node.mtime) + node.add_child(new_file_node) + + # For each subdir, create a node, walk its tree, add it as a child. + for d in dirs: + new_dir_node, new_max_mtime = _handle_dir(d) + max_mtime = max(max_mtime, new_max_mtime) + node.add_child(new_dir_node) + + return node, max_mtime diff --git a/src/boost/tools/build/test/unit_test.py b/src/boost/tools/build/test/unit_test.py new file mode 100644 index 00000000..da28503b --- /dev/null +++ b/src/boost/tools/build/test/unit_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +# Copyright 2003, 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test the unit_test rule. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +# Create the needed files. +t.write("jamroot.jam", """ +using testing ; +lib helper : helper.cpp ; +unit-test test : test.cpp : <library>helper ; +""") + +t.write("test.cpp", """ +void helper(); +int main() { helper(); } +""") + +t.write("helper.cpp", """ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +helper() {} +""") + +t.run_build_system(["link=static"]) +t.expect_addition("bin/$toolset/debug/link-static*/test.passed") + +t.cleanup() diff --git a/src/boost/tools/build/test/unit_tests.py b/src/boost/tools/build/test/unit_tests.py new file mode 100644 index 00000000..705764b6 --- /dev/null +++ b/src/boost/tools/build/test/unit_tests.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +# Copyright 2002, 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(pass_toolset=0) +t.run_build_system(["--debug", "--build-system=test/test"]) +t.cleanup() diff --git a/src/boost/tools/build/test/unused.py b/src/boost/tools/build/test/unused.py new file mode 100644 index 00000000..2b185d0d --- /dev/null +++ b/src/boost/tools/build/test/unused.py @@ -0,0 +1,81 @@ +#!/usr/bin/python + +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Test that unused sources are at least reported. + +import BoostBuild + +t = BoostBuild.Tester(["-d+2"], use_test_config=False) + +t.write("a.cpp", "int main() {}\n") +t.write("b.cpp", "\n") +t.write("b.xyz", "") +t.write("jamroot.jam", """\ +import "class" : new ; +import modules ; +import project ; +import targets ; +import type ; +import virtual-target ; + +type.register X : xyz ; + +class test-target-class : basic-target +{ + rule construct ( name : source-targets * : property-set ) + { + local result = [ property-set.empty ] ; + if ! [ modules.peek : GENERATE_NOTHING ] + { + result += [ virtual-target.from-file b.xyz : . : $(self.project) ] ; + if ! [ modules.peek : GENERATE_ONLY_UNUSABLE ] + { + result += [ virtual-target.from-file b.cpp : . : $(self.project) + ] ; + } + } + return $(result) ; + } + + rule compute-usage-requirements ( rproperties : targets * ) + { + return [ property-set.create <define>FOO ] ; + } +} + +rule make-b-main-target +{ + local project = [ project.current ] ; + targets.main-target-alternative [ new test-target-class b : $(project) ] ; +} + +exe a : a.cpp b c ; +make-b-main-target ; +alias c ; # Expands to nothing, intentionally. +""") + +t.run_build_system() + +# The second invocation should do nothing, and produce no warning. The previous +# invocation might have printed executed actions and other things, so it is not +# easy to check if a warning was issued or not. +t.run_build_system(stdout="") + +t.run_build_system(["-sGENERATE_ONLY_UNUSABLE=1"], stdout="") + +# Check that even if main target generates nothing, its usage requirements are +# still propagated to dependants. +t.write("a.cpp", """\ +#ifndef FOO + #error We refuse to compile without FOO being defined! + We_refuse_to_compile_without_FOO_being_defined +#endif +int main() {} +""") +t.run_build_system(["-sGENERATE_NOTHING=1"]) + +t.cleanup() diff --git a/src/boost/tools/build/test/use_requirements.py b/src/boost/tools/build/test/use_requirements.py new file mode 100644 index 00000000..36628150 --- /dev/null +++ b/src/boost/tools/build/test/use_requirements.py @@ -0,0 +1,283 @@ +#!/usr/bin/python + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2004, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + + +# Test that usage requirements on main targets work (and are propagated all the +# way up, and not only to direct dependants). +t.write("jamroot.jam", "") + +# Note: 'lib cc ..', not 'lib c'. If using 'lib c: ...' the HP-CXX linker will +# confuse it with the system C runtime. +t.write("jamfile.jam", """\ +lib b : b.cpp : <link>shared:<define>SHARED_B : : + <define>FOO <link>shared:<define>SHARED_B ; +lib cc : c.cpp b ; +exe a : a.cpp cc ; +""") + +t.write("b.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +#endif +foo() {} +""") + +t.write("c.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +#endif +create_lib_please() {} +""") + +t.write("a.cpp", """\ +#ifdef FOO +void +# if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +# endif +foo() {} +#endif +int main() { foo(); } +""") + +t.run_build_system() +t.run_build_system(["--clean"]) + + +# Test that use requirements on main target work, when they are referred using +# 'dependency' features. + +t.write("jamfile.jam", """\ +lib b : b.cpp : <link>shared:<define>SHARED_B : : <define>FOO + <link>shared:<define>SHARED_B ; +exe a : a.cpp : <use>b ; +""") + +t.write("b.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +#endif +foo() {} +""") + +t.write("a.cpp", """\ +#ifdef FOO +int main() {} +#endif +""") + +t.run_build_system() +t.run_build_system(["--clean"]) + + +# Test that usage requirements on a project work. +t.write("jamfile.jam", "exe a : a.cpp lib//b ;") + +t.write("lib/jamfile.jam", """\ +project + : requirements <link>shared:<define>SHARED_B + : usage-requirements <define>FOO <link>shared:<define>SHARED_B ; +lib b : b.cpp ; +""") + +t.write("lib/b.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +#endif +foo() {} +""") + +t.run_build_system() + + +# Test that use requirements are inherited correctly. +t.write("jamfile.jam", "exe a : a.cpp lib/1//b ;") + +t.write("a.cpp", """\ +#if defined(FOO) && defined(ZOO) +void foo() {} +#endif +int main() { foo(); } +""") + +t.write("lib/jamfile.jam", """\ +project : requirements : usage-requirements <define>FOO ; +""") + +t.write("lib/1/jamfile.jam", """\ +project + : requirements <link>shared:<define>SHARED_B + : usage-requirements <define>ZOO <link>shared:<define>SHARED_B ; +lib b : b.cpp ; +""") + +t.write("lib/1/b.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +#endif +foo() {} +""") + +t.run_build_system() +t.run_build_system(["--clean"]) + + +# Test that we correctly handle dependency features in usage requirements on +# target. +t.write("jamfile.jam", """\ +lib b : b.cpp : <link>shared:<define>SHARED_B : : <define>FOO + <link>shared:<define>SHARED_B ; + +# Here's the test: we should correctly handle dependency feature and get usage +# requirements from 'b'. +lib cc : c.cpp : <link>shared:<define>SHARED_C : : <library>b ; + +# This will build only if <define>FOO was propagated from 'c'. +exe a : a.cpp cc ; +""") + +t.write("a.cpp", """\ +#ifdef FOO +void +# if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +# endif +foo(); +#endif + +int main() { foo(); } +""") + +t.write("c.cpp", """\ +int +#if defined(_WIN32) && defined(SHARED_C) +__declspec(dllexport) +#endif +must_export_something; +""") + +t.run_build_system() +t.run_build_system(["--clean"]) + + +# Test correct handling of dependency features in project requirements. +t.write("jamfile.jam", "exe a : a.cpp lib1//cc ;") + +t.write("lib1/jamfile.jam", """\ +project + : requirements <link>shared:<define>SHARED_C + : usage-requirements <library>../lib2//b <link>shared:<define>SHARED_C ; +lib cc : c.cpp ; +""") + +t.write("lib1/c.cpp", """\ +int +#if defined(_WIN32) && defined(SHARED_C) +__declspec(dllexport) +#endif +must_export_something; +""") + +t.write("lib2/jamfile.jam", """\ +lib b : b.cpp : <link>shared:<define>SHARED_B : : <define>FOO + <link>shared:<define>SHARED_B ; +""") + +t.copy("b.cpp", "lib2/b.cpp") + +t.run_build_system() + + +# Test that targets listed in dependency features in usage requirements are +# built with the correct properties. +t.rm(".") + +t.write("jamroot.jam", "") +t.write("jamfile.jam", """\ +lib main : main.cpp : <use>libs//lib1 : : <library>libs//lib1 ; +exe hello : hello.cpp main : ; +""") + +t.write("main.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_LIB1) +__declspec(dllimport) +#endif +foo(); + +int main() { foo(); } +""") + +t.write("hello.cpp", "\n") +t.write("libs/a.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_LIB1) +__declspec(dllexport) +#endif +foo() {} +""") + + +# This library should be built with the same properties as 'main'. This is a +# regression test for a bug when they were generated with empty properties, and +# there were ambiguities between variants. +t.write("libs/jamfile.jam", """\ +lib lib1 : a_d.cpp : <variant>debug <link>shared:<define>SHARED_LIB1 : : + <link>shared:<define>SHARED_LIB1 ; +lib lib1 : a.cpp : <variant>release <link>shared:<define>SHARED_LIB1 : : + <link>shared:<define>SHARED_LIB1 ; +""") + +t.write("libs/a_d.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_LIB1) +__declspec(dllexport) +#endif +foo() {} +""") + +t.run_build_system(["link=static"]) +t.expect_addition("libs/bin/$toolset/debug/link-static*/a_d.obj") + + +# Test that indirect conditionals are respected in usage requirements. +t.rm(".") + +t.write("jamroot.jam", """\ +rule has-foo ( properties * ) { return <define>HAS_FOO ; } +exe a : a.cpp b ; +lib b : b.cpp : <link>static : : <conditional>@has-foo ; +""") + +t.write("a.cpp", """\ +#ifdef HAS_FOO +void foo(); +int main() { foo(); } +#endif +""") + +t.write("b.cpp", """\ +void +#if defined(_WIN32) && defined(SHARED_B) +__declspec(dllexport) +#endif +foo() {} +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/using.py b/src/boost/tools/build/test/using.py new file mode 100644 index 00000000..495f412b --- /dev/null +++ b/src/boost/tools/build/test/using.py @@ -0,0 +1,32 @@ +#!/usr/bin/python + +# Copyright (C) Vladimir Prus 2005. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamroot.jam", "using some_tool ;") +t.write("some_tool.jam", """\ +import project ; +project.initialize $(__name__) ; +rule init ( ) { } +""") + +t.write("some_tool.py", """\ +from b2.manager import get_manager +get_manager().projects().initialize(__name__) +def init(): + pass +""") + +t.write("sub/a.cpp", "int main() {}\n") +t.write("sub/jamfile.jam", "exe a : a.cpp ;") + +t.run_build_system(subdir="sub") +t.expect_addition("sub/bin/$toolset/debug*/a.exe") + +t.cleanup() diff --git a/src/boost/tools/build/test/wrapper.py b/src/boost/tools/build/test/wrapper.py new file mode 100644 index 00000000..1adeb2c9 --- /dev/null +++ b/src/boost/tools/build/test/wrapper.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +# Copyright 2004 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Test that the user can define his own rule that will call built-in main target +# rule and that this will work. + +import BoostBuild + + +t = BoostBuild.Tester(use_test_config=False) + +t.write("jamfile.jam", """ +my-test : test.cpp ; +""") + +t.write("test.cpp", """ +int main() {} +""") + +t.write("jamroot.jam", """ +using testing ; + +rule my-test ( name ? : sources + ) +{ + name ?= test ; + unit-test $(name) : $(sources) ; # /site-config//cppunit /util//testMain ; +} + +IMPORT $(__name__) : my-test : : my-test ; +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/test.passed") + +t.cleanup() diff --git a/src/boost/tools/build/test/wrong_project.py b/src/boost/tools/build/test/wrong_project.py new file mode 100644 index 00000000..7183a606 --- /dev/null +++ b/src/boost/tools/build/test/wrong_project.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +# Copyright Vladimir Prus 2005. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# Regression test. When Jamfile contained "using whatever ; " and the 'whatever' +# module declared a project, then all targets in Jamfile were considered to be +# declared in the project associated with 'whatever', not with the Jamfile. + +import BoostBuild + +t = BoostBuild.Tester(use_test_config=False) + +t.write("a.cpp", "int main() {}\n") + +t.write("jamroot.jam", """\ +using some_tool ; +exe a : a.cpp ; +""") + +t.write("some_tool.jam", """\ +import project ; +project.initialize $(__name__) ; +rule init ( ) { } +""") + +t.write("some_tool.py", """\ +from b2.manager import get_manager +get_manager().projects().initialize(__name__) +def init(): + pass +""") + +t.run_build_system() +t.expect_addition("bin/$toolset/debug*/a.exe") + +t.cleanup() |