From 8c5d400a01f307aa7ef91366e390eb73b7551ba0 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Thu, 21 Feb 2002 09:57:19 +0000 Subject: Implement the -u option (Task 39028). (Steve Leblanc) --- doc/man/scons.1 | 43 +++++++++---------- src/CHANGES.txt | 8 ++++ src/RELEASE.txt | 4 +- src/engine/SCons/Scanner/C.py | 4 +- src/engine/SCons/Script/__init__.py | 84 ++++++++++++++++++++++++++++--------- test/option-u.py | 48 ++++++++++++++++++--- 6 files changed, 141 insertions(+), 50 deletions(-) diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 78bf54b..ef5b664 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -147,18 +147,18 @@ built: scons src/subdir .EE -.\" or changing directory and invoking scons with the -.\" .B -u -.\" option, which traverses up the directory -.\" hierarchy until it finds the -.\" .I SConstruct -.\" file, and then builds -.\" targets relatively to the current subdirectory: -.\" -.\" .ES -.\" cd src/subdir -.\" scons -u . -.\" .EE +or by changing directory and invoking scons with the +.B -u +option, which traverses up the directory +hierarchy until it finds the +.I SConstruct +file, and then builds +targets relatively to the current subdirectory: + +.ES +cd src/subdir +scons -u . +.EE .B scons supports building multiple targets in parallel via a @@ -482,15 +482,16 @@ Ignored for compatibility with GNU appear up-to-date is unnecessary when using .BR scons .) -.\" .TP -.\" -u -.\" Traverse up directories until an -.\" .I SConstruct -.\" or -.\" .I sconstruct -.\" file is found, and use that -.\" as the top of the directory tree. Only targets at or below the -.\" current directory will be built. +.TP +-u +Walks up the directory structure until an +.I SConstruct , +.I Sconstruct +or +.I sconstruct +file is found, and uses that +as the top of the directory tree. Only targets at or below the +current directory will be built. .TP -v, --version diff --git a/src/CHANGES.txt b/src/CHANGES.txt index b364ac7..3b0f2b7 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -68,10 +68,18 @@ RELEASE 0.05 - - Efficiency: don't scan dependencies more than once during the walk of a tree. + From Steve Leblanc: + + - Add support for the -u option. + + - Add .cc and .hh file suffixes to the C Scanner. + From Anthony Roach: - Make the scons script return an error code on failures. + - Add support for using code to generate a command to build a target. + RELEASE 0.04 - Wed, 30 Jan 2002 11:09:42 -0600 diff --git a/src/RELEASE.txt b/src/RELEASE.txt index 467677b..358a359 100644 --- a/src/RELEASE.txt +++ b/src/RELEASE.txt @@ -98,8 +98,8 @@ RELEASE 0.04 - Wed, 30 Jan 2002 11:09:42 -0600 - No support yet for the following command-line options: -d -e -l --list-actions --list-derived --list-where - -o -p -q -r -R --random -u -w --write-filenames -W - --warn-undefined-variables + -o -p -q -r -R --random -w --write-filenames -W + --warn-undefined-variables Thank you for your interest, and please let us know how we can help improve SCons for your needs. diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py index 51235c3..6b5b6c6 100644 --- a/src/engine/SCons/Scanner/C.py +++ b/src/engine/SCons/Scanner/C.py @@ -43,8 +43,8 @@ include_cache = {} def CScan(fs = SCons.Node.FS.default_fs): "Return a prototype Scanner instance for scanning C/C++ source files" cs = CScanner(scan, "CScan", [fs, ()], - [".c", ".C", ".cxx", ".cpp", ".c++", - ".h", ".H", ".hxx", ".hpp"]) + [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", + ".h", ".H", ".hxx", ".hpp", ".hh"]) cs.fs = fs return cs diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index dfd969e..6e923bc 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -126,6 +126,8 @@ ignore_errors = 0 keep_going_on_error = 0 help_option = None print_tree = 0 +climb_up = 0 +target_top = None exit_status = 0 # exit status, assume success by default # utility functions @@ -353,7 +355,6 @@ def options_init(): def opt_C(opt, arg): try: os.chdir(arg) - SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd()) except: sys.stderr.write("Could not change directory to 'arg'\n") @@ -514,7 +515,11 @@ def options_init(): short = 's', long = ['silent', 'quiet'], help = "Don't print commands.") - Option(func = opt_not_yet, future = 1, + def opt_u(opt, arg): + global climb_up + climb_up = 1 + + Option(func = opt_u, short = 'u', long = ['up', 'search-up'], help = "Search up directory tree for SConstruct.") @@ -578,6 +583,18 @@ options_init() +def _SConstruct_exists(dirname=''): + """This function checks that an SConstruct file exists in a directory. + If so, it returns the path of the file. By default, it checks the + current directory. + """ + for file in ['SConstruct', 'Sconstruct', 'sconstruct']: + sfile = os.path.join(dirname, file) + if os.path.isfile(sfile): + return sfile + return None + + def UsageString(): help_opts = filter(lambda x: x.helpline, option_list) s = "Usage: scons [OPTION] [TARGET] ...\n" + "Options:\n" + \ @@ -587,7 +604,7 @@ def UsageString(): def _main(): - global scripts, num_jobs, task_class, calc + global scripts, num_jobs, task_class, calc, target_top targets = [] @@ -625,11 +642,27 @@ def _main(): targets.append(a) SCons.Script.SConscript._scons_add_args(xmit_args) + if climb_up: + target_top = '' # directory to prepend to targets + script_dir = os.getcwd() # location of script + while script_dir and not _SConstruct_exists(script_dir): + script_dir, last_part = os.path.split(script_dir) + if last_part: + target_top = os.path.join(last_part, target_top) + else: + script_dir = '' + if script_dir: + print "scons: Entering directory %s" % script_dir + os.chdir(script_dir) + else: + raise UserError, "No SConstruct file found." + + SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd()) + if not scripts: - for file in ['SConstruct', 'Sconstruct', 'sconstruct']: - if os.path.isfile(file): - scripts.append(file) - break + sfile = _SConstruct_exists() + if sfile: + scripts.append(sfile) if help_option == 'H': print UsageString() @@ -671,19 +704,30 @@ def _main(): if not targets: targets = SCons.Script.SConscript.default_targets - - def Entry(x): - if isinstance(x, SCons.Node.Node): - return x - try: - node = SCons.Node.FS.default_fs.Entry(x, create = 0) - except UserError: - str = "scons: *** Do not know how to make target `%s'." % x - if not keep_going_on_error: - sys.stderr.write(str + " Stop.\n") - sys.exit(2) - sys.stderr.write(str + "\n") - node = None + + if target_top: + target_top = SCons.Node.FS.default_fs.Dir(target_top) + + def Entry(x, top = target_top): + if isinstance(x, SCons.Node.Node): + node = x + else: + try: + node = SCons.Node.FS.default_fs.Entry(x, + directory = top, + create = 0) + except UserError: + string = "scons: *** Do not know how to make target `%s'." % x + if not keep_going_on_error: + sys.stderr.write(string + " Stop.\n") + sys.exit(2) + sys.stderr.write(string + "\n") + node = None + if top and not node.is_under(top): + if isinstance(node, SCons.Node.FS.Dir) and top.is_under(node): + node = top + else: + node = None return node nodes = filter(lambda x: x is not None, map(Entry, targets)) diff --git a/test/option-u.py b/test/option-u.py index 9f68ac5..dbeec6a 100644 --- a/test/option-u.py +++ b/test/option-u.py @@ -24,16 +24,54 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import TestSCons -import string +import os.path import sys +import TestSCons + test = TestSCons.TestSCons() -test.write('SConstruct', "") +python = sys.executable + +test.subdir('sub1', 'sub2', 'sub3') + +test.write('build.py', r""" +import sys +contents = open(sys.argv[2], 'rb').read() +file = open(sys.argv[1], 'wb') +file.write(contents) +file.close() +""") + +test.write('SConstruct', """ +B = Builder(name='B', action='%s build.py $TARGET $SOURCES') +env = Environment(BUILDERS = [B]) +env.B(target = 'sub1/foo.out', source = 'sub1/foo.in') +Default('.') +Export('env') +SConscript('sub2/SConscript') +env.B(target = 'sub3/baz.out', source = 'sub3/baz.in') +""" % python) + +test.write(['sub2', 'SConscript'], """ +Import('env') +env.B(target = 'bar.out', source = 'bar.in') +""") + +test.write(['sub1', 'foo.in'], "sub1/foo.in") +test.write(['sub2', 'bar.in'], "sub2/bar.in") +test.write(['sub3', 'baz.in'], "sub3/baz.in") + +test.run(arguments = '-u foo.out', chdir = 'sub1') + +test.fail_test(test.read(['sub1', 'foo.out']) != "sub1/foo.in") +test.fail_test(os.path.exists(test.workpath('sub2', 'bar.out'))) +test.fail_test(os.path.exists(test.workpath('sub3', 'baz.out'))) + +test.run(chdir = 'sub2', arguments = '-u') -test.run(arguments = '-u', - stderr = "Warning: the -u option is not yet implemented\n") +test.fail_test(test.read(['sub2', 'bar.out']) != "sub2/bar.in") +test.fail_test(os.path.exists(test.workpath('sub3', 'baz.out'))) test.pass_test() -- cgit v0.12