Index: tools/build/v2/build/generators.jam
===================================================================
--- tools/build/v2/build/generators.jam	(revision 45477)
+++ tools/build/v2/build/generators.jam	(working copy)
@@ -107,6 +107,7 @@
     import virtual-target ;
     import "class" : new ;
     import property ;
+    import path ;
 
     EXPORT class@generator : indent increase-indent decrease-indent generators.dout ;
 
@@ -377,6 +378,52 @@
         return $(result) ;
     }
 
+    rule add-prefix ( name : prefix ? )
+    {
+        if $(prefix)
+        {               
+            name = $(prefix)$(name) ;
+            name = $(name:J=) ;
+        }
+        return $(name) ;
+    }
+
+    rule add-postfix ( name : postfix ? )
+    {   
+        if $(postfix)
+        {               
+            name = $(name)$(postfix) ;
+            name = $(name:J=) ;
+        }
+        return $(name) ;
+    }
+
+    # Determine target name from fullname (maybe including path components)
+    # Place optional prefix and postfix around basename
+    #
+    rule determine-target-name ( fullname  : prefix ? postfix ? )
+    {
+        # See if we need to add directory to the target name.
+        local dir  = $(fullname:D) ;            
+        local name = $(fullname:B) ; 
+        
+        name = [ add-prefix  $(name) : $(prefix) ] ;
+        name = [ add-postfix $(name) : $(postfix) ] ;
+
+        if $(dir) && 
+          # Never append '..' to target path.
+          ! [ MATCH .*(\\.\\.).* : $(dir) ] 
+            && 
+          ! [ path.is-rooted $(dir) ]
+        {
+            # Relative path is always relative to the source
+            # directory. Retain it, so that users can have files
+            # with the same in two different subdirectories.
+            name = $(dir)/$(name) ;                
+        }            
+        return $(name) ;
+    }
+
     # Determine the name of the produced target from the names of the sources.
     #
     rule determine-output-name ( sources + )
@@ -399,10 +446,7 @@
                 errors.error "$(self.id): source targets have different names: cannot determine target name" ;
             }
         }
-
-        # Names of sources might include directory. We should strip it.
-        name = $(name:D=) ;
-
+        name = [ determine-target-name [ $(sources[1]).name ] ] ;
         return $(name) ;
     }
 
@@ -445,7 +489,7 @@
         local post = $(self.name-postfix) ;
         for local t in $(self.target-types)
         {
-            local generated-name = $(pre[1])$(name)$(post[1]) ;
+            local generated-name = [ determine-target-name $(name) : $(pre[1]) $(post[1]) ] ;
             pre = $(pre[2-]) ;
             post = $(post[2-]) ;
 
Index: tools/build/v2/build/project.jam
===================================================================
--- tools/build/v2/build/project.jam	(revision 45477)
+++ tools/build/v2/build/project.jam	(working copy)
@@ -794,7 +794,17 @@
         # absolute.
         for local p in $(paths)
         {
-            result += [ path.root $(p) [ path.pwd ] ] ;
+            # If the path is below source location, use relative path.
+            # Otherwise, use full path just to avoid any ambiguities.
+            local rel = [ path.relative $(p) $(location) : no-error ] ;
+            if $(rel) = not-a-child
+            {                   
+                result += [ path.root $(p) [ path.pwd ] ] ;
+            }
+            else
+            {
+                result += $(rel) ;
+            }                
         }
     }
     else
Index: tools/build/v2/test/relative_sources.py
===================================================================
--- tools/build/v2/test/relative_sources.py	(revision 45477)
+++ tools/build/v2/test/relative_sources.py	(working copy)
@@ -10,10 +10,30 @@
 from BoostBuild import Tester
 t = Tester()
 
-t.write("project-root.jam", "import gcc ;")
-t.write("Jamfile", "exe a : src/a.cpp ;")
+# Test that relative path to source, 'src', is preserved.
+t.write("Jamroot", "exe a : src/a.cpp ;")
 t.write("src/a.cpp", "int main() { return 0; }\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", "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", "")
+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()
Index: tools/build/v2/util/path.jam
===================================================================
--- tools/build/v2/util/path.jam	(revision 45477)
+++ tools/build/v2/util/path.jam	(working copy)
@@ -375,8 +375,9 @@
 # Assuming 'child' is a subdirectory of 'parent', return the relative path from
 # 'parent' to 'child'.
 #
-rule relative ( child parent )
+rule relative ( child parent : no-error ? )
 {
+    local not-a-child ;
     if $(parent) = "."
     {
         return $(child) ;
@@ -395,12 +396,27 @@
             }
             else
             {
-                errors.error $(child) is not a subdir of $(parent) ;
+                not-a-child = true ;
+                split1 = ;
             }
         }
         if $(split2)
         {
-            return [ join $(split2) ] ;
+          if $(not-a-child)
+          {
+              if $(no-error)
+              {
+                  return not-a-child ;
+               }
+               else
+               {
+                   errors.error $(child) is not a subdir of $(parent) ;
+               }                        
+          }
+          else
+          {
+             return [ join $(split2) ] ;    
+          }        
         }
         else
         {

