Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yacc tool initialization on windows adding spurious paths to PATH causing build failure. #3336

Closed
jcbrill opened this issue Mar 27, 2019 · 17 comments
Assignees

Comments

@jcbrill
Copy link
Contributor

jcbrill commented Mar 27, 2019

Additional paths (possibly extraneous) are being added to the msvc environment path for SCons 3.0.5 as compared to SCons 3.0.4.

The following paths are added to the ENV['PATH'] after the msvc configuration in SCons 3.0.5:

    C:\ProgramData\chocolatey\bin
    C:\msys64
    C:\msys
    C:\cygwin64\bin
    C:\cygwin\bin
    C:\Program Files\Java\jdk1.8.0_172\bin

The following paths are added to the ENV['PATH'] after the msvc configuration in SCons 3.0.4:

    C:\Program Files\Java\jdk1.8.0_172\bin;

When configured from the command line using vcvarsall.bat, the JDK is not added to the path.

If nothing else, this appears to violate The Law of Least Astonishment.

Configuration:

  • Scons: 3.0.5
  • Python: 2.7.14 on win32
  • OS: Windows 7 (32-bit)

scons-users message: https://pairlist4.pair.net/pipermail/scons-users/2019-March/007658.html

The additional SCons added paths cause build failures when user-specified mingw-w64 tools are added to the path using AppendENVPath. In the test case, the cygwin/bin folder precedes the user desired mingw-w64 path that was manually added.

Due to the additional paths, PrependENVPath would have to be used instead to guarantee the desired tools would likely be invoked.

An annotated comparison of configurations of msvc 2005 and mingw-w64 from the command line, SCons 3.0.4 and SCons 3.0.5 is shown below. The same holds for all tested versions of MSVC.

Command-line msvs 2005 environment:

    set PATH=C:\Windows\System32
    set INCLUDE=
    set LIB=
    set LIBPATH=
    call vcvarsall.bat

    Path=C:\Program Files\Microsoft Visual Studio 8\Common7\IDE;               <== msvc [ok]
         C:\Program Files\Microsoft Visual Studio 8\VC\BIN;                    <== msvc [ok]
         C:\Program Files\Microsoft Visual Studio 8\Common7\Tools;             <== msvc [ok]
         C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\bin;         <== msvc [ok]
         C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\bin;        <== msvc [ok]
         C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin;              <== msvc [ok]
         C:\Windows\Microsoft.NET\Framework\v2.0.50727;                        <== msvc [ok]
         C:\Program Files\Microsoft Visual Studio 8\VC\VCPackages;             <== msvc [ok]
         C:\Windows\System32                                                   <== system [ok]

    LIB=C:\Program Files\Microsoft Visual Studio 8\VC\ATLMFC\LIB;              <== msvc [ok]
        C:\Program Files\Microsoft Visual Studio 8\VC\LIB;                     <== msvc [ok]
        C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\lib;         <== msvc [ok]
        C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\lib;               <== msvc [ok]

    LIBPATH=C:\Windows\Microsoft.NET\Framework\v2.0.50727;                     <== msvc [ok]
            C:\Program Files\Microsoft Visual Studio 8\VC\ATLMFC\LIB           <== msvc [ok]

    INCLUDE=C:\Program Files\Microsoft Visual Studio 8\VC\ATLMFC\INCLUDE;      <== msvc [ok]
            C:\Program Files\Microsoft Visual Studio 8\VC\INCLUDE;             <== msvc [ok]
            C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\include; <== msvc [ok]
            C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\include;       <== msvc [ok]

SCons 3.0.4 mingw build ENV{}:

    PATH: C:\\Windows\\System32;                                               <== system [ok]
          C:/Software/MINGW810-V6R0-WIN32SJLJ/mingw32/bin;                     <== user AppendENVPath [ok]
          C:/Software/MSVS141/VC/Tools/MSVC/14.16.27023/bin/HostX86/x86        <== user AppendENVPath [ok]

SCons 3.0.4 msvs 2005 build ENV{}:

    PATH: C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;          <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN;               <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;        <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin;   <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\bin;  <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\bin;        <== msvc [ok]
          C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727;                   <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\VC\\VCPackages;        <== msvc [ok]
          C:\\Windows\\System32;                                               <== system [ok]
          C:\\Windows\\System32\\Wbem;                                         <== system [ok]
? ==>     C:\\Program Files\\Java\\jdk1.8.0_172\\bin;                          <== SCONS [?]
          C:/Software/MINGW810-V6R0-WIN32SJLJ/mingw32/bin',                    <== user AppendENVPath [ok]

    LIB: C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\LIB;        <== msvc [ok]
         C:\\Program Files\\Microsoft Visual Studio 8\\VC\\LIB;                <== msvc [ok]
         C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\lib;   <== msvc [ok]
         C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\lib          <== msvc [ok]

    LIBPATH: C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727;                <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\LIB',   <== msvc [ok]

    INCLUDE: C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\INCLUDE;      <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\VC\\INCLUDE;              <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\include; <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\include;       <== msvc [ok]
             E:/Local/STK/include/c99_msinttypes;                                    <== user [ok]
             E:/Local/STK/include/c99_stdbool                                        <== user [ok]

SCons 3.0.5 mingw build ENV{}:

    PATH: C:\\Windows\\System32;                                               <== system [ok]            
          C:/Software/MINGW810-V6R0-WIN32SJLJ/mingw32/bin;                     <== user AppendENVPath [ok]
          C:/Software/MSVS141/VC/Tools/MSVC/14.16.27023/bin/HostX86/x86        <== user AppendENVPath [ok]

SCons 3.0.5 msvs 2005 build ENV{}:

    PATH: C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;          <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN;               <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;        <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin;   <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\bin;  <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\bin;        <== msvc [ok]
          C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727;                   <== msvc [ok]
          C:\\Program Files\\Microsoft Visual Studio 8\\VC\\VCPackages;        <== msvc [ok]
          C:\\Windows\\System32;                                               <== system [ok]
          C:\\Windows\\System32\\Wbem;                                         <== system [ok]
? ==>     C:\\ProgramData\\chocolatey\\bin;                                    <== SCONS [?]
? ==>     C:\\msys64;                                                          <== SCONS [?]
? ==>     C:\\msys;                                                            <== SCONS [?]
? ==>     C:\\cygwin64\\bin;                                                   <== SCONS [?]
? ==>     C:\\cygwin\\bin;                                                     <== SCONS [?]
? ==>     C:/Program Files\\Java\\jdk1.8.0_172\\bin;                           <== SCONS [?]
          C:/Software/MINGW810-V6R0-WIN32SJLJ/mingw32/bin                      <== user AppendENVPath [ok]

    LIB: C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\LIB;        <== msvc [ok]
         C:\\Program Files\\Microsoft Visual Studio 8\\VC\\LIB;                <== msvc [ok]
         C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\lib;   <== msvc [ok]
         C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\lib          <== msvc [ok]

    LIBPATH: C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727;                <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\LIB     <== msvc [ok]

    INCLUDE: C:\\Program Files\\Microsoft Visual Studio 8\\VC\\ATLMFC\\INCLUDE;      <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\VC\\INCLUDE;              <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\include; <== msvc [ok]
             C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\include;       <== msvc [ok]
             E:/Local/STK/include/c99_msinttypes;                                    <== user [ok]
             E:/Local/STK/include/c99_stdbool                                        <== user [ok]
@bdbaddog
Copy link
Contributor

Can you add a SConstruct to repro this?

@dmoody256
Copy link
Contributor

could this be related: #3287

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 27, 2019

I don't know if this helps, the following SConstruct file:

env = Environment(MSVC_VERSION="8.0", TARGET_ARCH="x86_64")
print env.Dump()

Produces this output:
sample_env.txt

Path (the paths marked do not exist):

           'PATH': 
                'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;
                 C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN\\x86_amd64;
                 C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN;
                 C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;
                 C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin;
                 C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\bin;
                 C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727;
                 C:\\Program Files\\Microsoft Visual Studio 8\\VC\\VCPackages;
                 C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\bin;
                 C:\\Windows\\System32;C:\\Windows\\System32\\Wbem;
=>            C:\\ProgramData\\chocolatey\\bin;
=>            C:\\msys64;
=>            C:\\msys;
=>            C:\\cygwin64\\bin;
                 C:\\cygwin\\bin;
                 C:/Program Files\\Java\\jdk1.8.0_172\\bin',

The marked builders are new in 3.0.5 and did not exist in 3.0.4:

  'BUILDERS': {
=>   'CFile': <SCons.Builder.CompositeBuilder object at 0x0236D030>, 
        'Zip': <SCons.Builder.BuilderBase object at 0x02357530>, 
        'MSVSProject': <SCons.Builder.BuilderBase object at 0x022D3BB0>, 
        'RES': <SCons.Builder.BuilderBase object at 0x022D3CD0>, 
        'TypeLibrary': <SCons.Builder.BuilderBase object at 0x02309D70>, 
        'StaticLibrary': <SCons.Builder.BuilderBase object at 0x02365F30>, 
        'PCH': <SCons.Builder.BuilderBase object at 0x022D3BF0>, 
        'Program': <SCons.Builder.BuilderBase object at 0x02357930>, 
        'ProgramAllAtOnce': <SCons.Builder.BuilderBase object at 0x02357B30>, 
=>   'Substfile': <SCons.Builder.BuilderBase object at 0x02357590>, 
=>   'CXXFile': <SCons.Builder.CompositeBuilder object at 0x0236D0B0>, 
        'Object': <SCons.Builder.CompositeBuilder object at 0x02357C70>, 
        'JavaClassDir': <SCons.Builder.BuilderBase object at 0x0236D350>, 
        'LoadableModule': <SCons.Builder.BuilderBase object at 0x02357BB0>, 
=>   'Textfile': <SCons.Builder.BuilderBase object at 0x02357810>, 
        'MSVSSolution': <SCons.Builder.BuilderBase object at 0x022D3BD0>, 
        'CopyAs': <SCons.Builder.BuilderBase object at 0x02357B50>, 
        'SharedLibrary': <SCons.Builder.BuilderBase object at 0x023578B0>, 
        'CopyTo': <SCons.Builder.BuilderBase object at 0x02357AD0>, 
        'StaticObject': <SCons.Builder.CompositeBuilder object at 0x02357C70>, 
        'SharedObject': <SCons.Builder.CompositeBuilder object at 0x02357D10>, 
        'JarFile': <SCons.Builder.BuilderBase object at 0x0236D1F0>, 
        'JavaClassFile': <SCons.Builder.BuilderBase object at 0x0236D290>, 
        'Library': <SCons.Builder.BuilderBase object at 0x02365F30>, 
        'RMIC': <SCons.Builder.BuilderBase object at 0x02326B70>, 
        'JavaFile': <SCons.Builder.CompositeBuilder object at 0x0236D2F0>
  },

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 27, 2019

Perhaps coming from the lex tool?

@mwichmann
Copy link
Collaborator

It's got to come from the stanza in Tool/__init__.py, where it steps through the passed-in paths from a tool (default_paths) and then, if there was a match, doesn't restore the saved PATH, which means that everything that was appended is kept, even the ones which didn't yield a match.

    # If that doesn't work try default location for mingw
    save_path = env['ENV']['PATH']
    for p in default_paths:
        env.AppendENVPath('PATH', p)
    path = env.WhereIs(key_program)
    if not path:
        env['ENV']['PATH'] = save_path
    return path

@mwichmann
Copy link
Collaborator

So a quick guess is this might help:


diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 74dba75c..820435b9 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -1338,8 +1338,9 @@ def find_program_path(env, key_program, default_paths=[]):
     for p in default_paths:
         env.AppendENVPath('PATH', p)
     path = env.WhereIs(key_program)
-    if not path:
-        env['ENV']['PATH'] = save_path
+    env['ENV']['PATH'] = save_path
+    if path:
+        env.AppendENVPath('PATH', path)
     return path
 
 # Local Variables:

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 27, 2019

The following SConstruct behaves as expected:

env = Environment(MSVC_VERSION="8.0", TARGET_ARCH="x86_64", tools=['mslink','msvc','mslib','msvs'])
print env.Dump()

Output:
sample_env2.txt

Path:

'PATH': 
    'C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;
     C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN\\x86_amd64;
     C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN;
     C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;
     C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin;
     C:\\Program Files\\Microsoft Visual Studio 8\\VC\\PlatformSDK\\bin;
     C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727;
     C:\\Program Files\\Microsoft Visual Studio 8\\VC\\VCPackages;
     C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\bin;
     C:\\Windows\\System32;C:\\Windows\\System32\\Wbem',

Explicitly listing the msvc/msvs tools results in the expected path construction. I'm guessing the reason that the tools were not specified explicitly was that the default construction (up until 3.0.5) was what was expected (with the addition of the JDK). The JDK addition now makes sense in terms of the default environment.

It appears that I'm the tool in this case.

@mwichmann
Copy link
Collaborator

The default tool set is intended to make things simpler, you don't have to figure out all the tools your project needs (if what you need is included in the defaults). Bill has concluded that it's quite a bit faster to not use the default set, and just list the ones you want, particularly on windows platforms. For what it's worth...

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 27, 2019

The irony is that for my builds the tools are passed for the mingw-w64 builds and explicit folders were being appended to the path for msvc builds. It was purely an oversight that the tools were not passed for msvc builds. In almost all cases I do not want cygwin silently added to the path. I learned something valuable moving forward.

@bdbaddog
Copy link
Contributor

bdbaddog commented Mar 28, 2019 via email

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 28, 2019

I will try to apply the patch later today.

The patch will not change the build failure that I experienced. My build script must be changed to accommodate the default SCons 3.0.5 behavior in one of two ways: (1) explicitly pass the tools for msvc to the environment and use AppendENVPath for dlltool or (2) make no changes to the environment and change AppendENVPath for dlltool to PrependENVTool. I have elected the first option.

To recap: there are paths added to the default environment ENV[PATH] that do not exist on my computer. I suppose that is a bug. The two line SConstruct file attached above demonstrates and simply reproduces this behavior. Any version of MSVC could be passed to the environment (or probably even none at all). Paths that don't exist really have no effect other that polluting the path.

The build failure that I experienced is because one of the additional paths added to the default environment ENV[PATH] constuction does exist (cygwin/bin). Cygwin/bin contains flex.exe (which is what I suspect SCons was looking for) and also a variety of gcc/mingw tools. The path location that I eventually add manually to the end of the ENV[PATH] using AppendENVPath for the desired dlltool executable is meaningless since there is already a dlltool in the path. This is not a bug but an unintended consequence of the construction of the default environment.

If I understand the patch correctly, paths that do not exist will not be added to the path. That's all well and good. However my problem was with an unintended consequence of an added path that does exist conflicting with my expectations of behavior based on SCons 3.0.4 and earlier. The only solution to my build problem is to change my script as described earlier.

I fear that adding cygwin to the path may break a number of scripts that are using AppendENVPath to explicitly add tools to the default environment.

@mwichmann
Copy link
Collaborator

I will try to apply the patch later today.

The patch will not change the build failure that I experienced.
...
To recap: there are paths added to the default environment ENV[PATH] that do not exist on my computer. I suppose that is a bug.

That was the idea of the tiny patch: right now all the extra "possible places something could be found" are added as they are tried, and as long as the process ended with a "hit", they're kept; instead I try to keep just the "hit".

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 28, 2019

I just tried the first test.

Good news: folders that don't exist are not added to the path.
Bad news: the fully qualified executable is added to the path as well as the folder to the path:

C:\\cygwin\\bin\\flex.EXE;
C:\\cygwin\\bin;
C:\\Program Files\\Java\\jdk1.8.0_172\\bin\\jar.EXE;
C:\\Program Files\\Java\\jdk1.8.0_172\\bin',

@mwichmann
Copy link
Collaborator

Oh, I was afraid of that, wasn't sure if it came back as a directory or as a full path. More thinking then - thanks for the quick update!

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 28, 2019

I don't think you need to add the path when it exists as the calling procedure likely will. The following seems to work:

Original 3.0.5 code:

    # If that doesn't work try default location for mingw
    save_path = env['ENV']['PATH']
    for p in default_paths:
        env.AppendENVPath('PATH', p)
    path = env.WhereIs(key_program)
    if not path:
        env['ENV']['PATH'] = save_path
    return path

Modified 3.0.5 code:

    # If that doesn't work try default location for mingw
    save_path = env['ENV']['PATH']
    for p in default_paths:
        env.AppendENVPath('PATH', p)
    path = env.WhereIs(key_program)
    env['ENV']['PATH'] = save_path
    return path

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 28, 2019

The implications of the following excerpt from the 3.0.5 release email now makes a lot more sense:

SCons 3.0.5 Released

FIXES

  - Add default paths for yacc tool on windows to include cygwin, mingw, and chocolatey

mwichmann added a commit to mwichmann/scons that referenced this issue Mar 28, 2019
When tool modules initialize, they check paths to decide if
the underlying tool is actually present.  The current checker adds
any "default paths" the caller may have supplied (locations like
mingw, cygwin, chocolatey install locations, etc.); if there is
match from this list, any previous default paths are also kept.
To avoid keeping these non-matching paths, restore the original PATH;
the caller is responsible for adding to PATH if necessary.
Docstring now says so.

Note lex and yacc tool modules seem to expect the path-modifying
behavior that's being gotten rid of - so they preseve the path
first and restore it after.  The change here won't break those,
but makes the extra behavior unneeded - could remove it.

Signed-off-by: Mats Wichmann <[email protected]>
mwichmann added a commit to mwichmann/scons that referenced this issue Mar 28, 2019
When tool modules initialize, they check paths to decide if
the underlying tool is actually present.  The current checker adds
any "default paths" the caller may have supplied (locations like
mingw, cygwin, chocolatey install locations, etc.); if there is
match from this list, any previous default paths are also kept.
To avoid keeping these non-matching paths, restore the original PATH;
the caller is responsible for adding to PATH if necessary.
Docstring now says so.

Note lex and yacc tool modules seem to expect the path-modifying
behavior that's being gotten rid of - so they preseve the path
first and restore it after.  The change here won't break those,
but makes the extra behavior unneeded - could remove it.

Signed-off-by: Mats Wichmann <[email protected]>
@bdbaddog bdbaddog changed the title 3.0.5 msvc env path construction problem Yacc tool initialization on windows adding spurious paths to PATH causing build failure. Apr 2, 2019
mwichmann added a commit to mwichmann/scons that referenced this issue Apr 13, 2019
When tool modules initialize, they check paths to decide if
the underlying tool is actually present.  The current checker adds
any "default paths" the caller may have supplied (locations like
mingw, cygwin, chocolatey install locations, etc.); if there is
match from this list, any previous default paths are also kept.
To avoid keeping these non-matching paths, restore the original PATH;
the caller is responsible for adding to PATH if necessary.
Docstring now says so.

Note lex and yacc tool modules seem to expect the path-modifying
behavior that's being gotten rid of - so they preseve the path
first and restore it after.  The change here won't break those,
but makes the extra behavior unneeded - could remove it.

Signed-off-by: Mats Wichmann <[email protected]>
bdbaddog added a commit that referenced this issue Apr 24, 2019
[#3336] do not add not-found tool paths
@bdbaddog
Copy link
Contributor

Should be resolved in master now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants