Repository: SCons/scons

Issue:
Build failed with MSVC_BATCH and spaces in path
When target dir path has spaces and MSVC_BATCH set to true  - cl.exe failed.
Actually it is cl.exe "feature" - Target dir needs to end with slash, not backslash. 
In SCons code msvc_output_flag function return '/Fo${TARGET.dir}' + os.sep
Should be '/Fo${TARGET.dir}/'
Here is confirmation https://social.msdn.microsoft.com/Forums/vstudio/en-US/c5992cfc-083a-4472-bf1d-e3151cae2f32/clexe-how-to-setup-path-for-objects-dir-fo-which-contains-spaces?forum=vcgeneral




Discussion:
Can you bring this issue to the scons users mailing list? We prefer that such are discussed there before a bug is filed.
This get's more eyes on the issue, provides workarounds, prevents duplicate bugs, and also invalid bugs from getting files.

Can you create an example to reproduce this? Preferrable a single SConstruct? and/or zip file with a couple source files and an SConstruct?

Resolving patch:
diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py
--- a/src/engine/SCons/Tool/msvc.py
+++ b/src/engine/SCons/Tool/msvc.py
@@ -195,7 +195,10 @@ def msvc_output_flag(target, source, env, for_signature):
         # that the test(s) for this can be run on non-Windows systems
         # without having a hard-coded backslash mess up command-line
         # argument parsing.
-        return '/Fo${TARGET.dir}' + os.sep
+        # Adding double os.sep's as if the TARGET.dir has a space or otherwise
+        # needs to be quoted they are needed per MSVC's odd behavior
+        # See: https://github.com/SCons/scons/issues/3106
+        return '/Fo${TARGET.dir}' + os.sep*2
 
 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR",
                               batch_key=msvc_batch_key,


Test patch:
diff --git a/test/MSVC/MSVC_BATCH-spaces-targetdir.py b/test/MSVC/MSVC_BATCH-spaces-targetdir.py
new file mode 100644
--- /dev/null
+++ b/test/MSVC/MSVC_BATCH-spaces-targetdir.py
@@ -0,0 +1,11 @@
+import TestSCons
+
+
+
+test = TestSCons.TestSCons()
+
+test.skip_if_not_msvc()
+
+
+test.dir_fixture('MSVC_BATCH-spaces-targetdir')
+test.run()
\ No newline at end of file
diff --git a/test/MSVC/MSVC_BATCH-spaces-targetdir/SConstruct b/test/MSVC/MSVC_BATCH-spaces-targetdir/SConstruct
new file mode 100644
--- /dev/null
+++ b/test/MSVC/MSVC_BATCH-spaces-targetdir/SConstruct
@@ -0,0 +1,8 @@
+import os.path
+
+env=Environment(MSVC_BATCH=True)
+
+td='tar ge tdir'
+VariantDir(td,'src')
+env.Program(os.path.join(td,'test_program'),
+            [os.path.join(td,a) for a in ['a.c','b.c','c.c']])
diff --git a/test/MSVC/MSVC_BATCH-spaces-targetdir/src/a.c b/test/MSVC/MSVC_BATCH-spaces-targetdir/src/a.c
new file mode 100644
--- /dev/null
+++ b/test/MSVC/MSVC_BATCH-spaces-targetdir/src/a.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+extern void myfuncb();
+extern void myfuncc();
+
+
+void myfunca() {
+    printf("myfunca\n");
+}
+
+int main(int argc, char *argv[]) {
+    myfunca();
+    myfuncb();
+    myfuncc();
+}
\ No newline at end of file
diff --git a/test/MSVC/MSVC_BATCH-spaces-targetdir/src/b.c b/test/MSVC/MSVC_BATCH-spaces-targetdir/src/b.c
new file mode 100644
--- /dev/null
+++ b/test/MSVC/MSVC_BATCH-spaces-targetdir/src/b.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void myfuncb() {
+    printf("myfuncb\n");
+}
\ No newline at end of file
diff --git a/test/MSVC/MSVC_BATCH-spaces-targetdir/src/c.c b/test/MSVC/MSVC_BATCH-spaces-targetdir/src/c.c
new file mode 100644
--- /dev/null
+++ b/test/MSVC/MSVC_BATCH-spaces-targetdir/src/c.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void myfuncc() {
+    printf("myfuncc\n");
+}
\ No newline at end of file
diff --git a/test/MSVC/batch.py b/test/MSVC/batch.py
--- a/test/MSVC/batch.py
+++ b/test/MSVC/batch.py
@@ -32,6 +32,7 @@
 platform.
 """
 
+import os
 import TestSCons
 
 test = TestSCons.TestSCons()
@@ -72,6 +73,7 @@
 """)
 
 test.write('SConstruct', """
+DefaultEnvironment(tools=[])
 cccom = r'%(_python_)s fake_cl.py $_MSVC_OUTPUT_FLAG $CHANGED_SOURCES'
 linkcom = r'%(_python_)s fake_link.py ${TARGET.windows} $SOURCES'
 env = Environment(tools=['msvc', 'mslink'],
@@ -96,8 +98,8 @@
 
 test.must_match('prog.exe', "prog.c\nf1.c\nf2.c\n", mode='r')
 test.must_match('fake_cl.log', """\
-/Fo. prog.c f1.c f2.c
-""", mode='r')
+/Fo.%s prog.c f1.c f2.c
+"""%os.sep, mode='r')
 
 test.up_to_date(options = 'MSVC_BATCH=1', arguments = '.')
 
@@ -109,9 +111,9 @@
 
 test.must_match('prog.exe', "prog.c\nf1.c 2\nf2.c\n", mode='r')
 test.must_match('fake_cl.log', """\
-/Fo. prog.c f1.c f2.c
-/Fo. f1.c
-""", mode='r')
+/Fo.%s prog.c f1.c f2.c
+/Fo.%s f1.c
+"""%(os.sep, os.sep), mode='r')
 
 test.up_to_date(options = 'MSVC_BATCH=1', arguments = '.')