Skip to content

Conversation

@jcbrill
Copy link
Contributor

@jcbrill jcbrill commented Apr 11, 2022

This PR is a proposed fix for #2813.

Requisite documentation is incomplete.

Contributor Checklist:

  • I have created a new test or updated the unit tests to cover the new/changed functionality.
  • I have updated CHANGES.txt (and read the README.rst)
  • I have updated the appropriate documentation

My TODO list:

  • Code: Minor tweak to initialization/data structure (keep external symbol and internal value together)
  • Code: Docstring above
  • Docs: CHANGES.txt
  • Docs: RELEASE.txt
  • Docs: Documentation for environment variable MSVC_NOTFOUND_POLICY
  • Docs: Documentation for functions set_msvc_notfound_policy and get_msvc_notfound_policy (see below)?
  • Docs: Add docstring for functions set_msvc_notfound_policy and get_msvc_notfound_policy
  • Test: Test request below
  • Issue: File enhancement issue to set notfound policy as a command-line option

Also need to test:

What happens if the user runs the MSVC developer shell and does
env=Environment(ENV=os.environ)
Will this still work/not issue warnings for the defaulted MSVC_VERSION case?

Should and where would the set_msvc_notfound_policy and get_msvc_notfound_policy functions be documented?
Added docstrings for set_msvc_notfound_policy and get_msvc_notfound_policy as discussed below.

…etup_env with undefined MSVC_VERSION (default tools).
@bdbaddog
Copy link
Contributor

Looks good.
I'm thinking for the case where the user requests a version, you can also eliminate duplicate messaging by adding similar logic keyed on msvc_version,host_arch,target_arch in msvc_find_valid_batch_script() ?

Also.. how to test this?

@bdbaddog bdbaddog linked an issue Apr 11, 2022 that may be closed by this pull request
@bdbaddog bdbaddog added Op Sys: Windows MSVC Microsoft Visual C++ Support labels Apr 11, 2022
@bdbaddog bdbaddog self-requested a review April 11, 2022 17:40
@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 11, 2022

I'm thinking for the case where the user requests a version, you can also eliminate duplicate messaging by adding similar logic keyed on msvc_version,host_arch,target_arch in msvc_find_valid_batch_script() ?

Making the warning an exception solves the duplicate message problem :)

Fail early and often. I'm only half kidding. I prefer an exception to a build that fails because cl.exe is not found. I'm probably in the minority though. Famous last words: "how hard could it be?". I shall investigate.

Also.. how to test this?

I'm assuming you mean adding a unit test.

In the discussion for #2813, I used a vm without MSVS and mingw. It might be possible to "borrow" the fake registry and fake vswhere fixtures/code so that no MSVS instances are detected. I think at that point all that is needed is an environment that initializes. That step is beyond my current abilities. Might need to poke around.

@bdbaddog
Copy link
Contributor

@jcbrill - indeed if you request a specific version and it's not there, throwing an exception and exiting is WAY better than "can't find cl.exe"...

It might be reasonable to just make a unit test (such that vswhere and registry are never hit) for the test.
Those are always faster.. And honestly preferrable as long they realistically simulate the "fault" you want to ensure doesn't return or the new feature.

@bdbaddog
Copy link
Contributor

If you mocked get_default_version() and just called msvc_setup_env().. it's probably doable?
To test what you have already.
And then further testing msvc_setup_env() in some mocked environment might also suffice.
I'll take a look a bit later today.

@mwichmann
Copy link
Collaborator

I'm in the midst of stuff and can't check - we should definitely have a way to mock the registry-fishing stuff, I kinda thought I'd seen such in some test but maybe it was some other context.

@bdbaddog
Copy link
Contributor

I'm in the midst of stuff and can't check - we should definitely have a way to mock the registry-fishing stuff, I kinda thought I'd seen such in some test but maybe it was some other context.

Yup. There's mocked registry tests for sure.

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 11, 2022

@bdbaddog I will look either later tonight or first thing in morning, but I THINK there may be multiple warnings due to the warning being issued inside the loop checking for host/target combinations. Each host/target fails because it does not exist and then just falls off the end of the loop end effectively returns an empty dictionary. If that is what is happending, a simple flag/count could be added to issue the warning once and then, if desired, raise an exception when the nothing was found instead of returning an empty dictionary.

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 11, 2022

It may be even simpler than what I described. Need to check existing code and one of the PRs. The warning might be able to be suppressed altogether (commented out) and an exception raised prior to exit based on the dictionary being empty. Need to make sure the conditions under which this would happen (make sure does not effect default tool initialization).

…efined dictionary when attempting to find a valid msvc batch script. Raise an MSVCVersionNotFound exception when the default msvc version is requested and there are no msvc versions installed. Suppress raising an MSVCVersionNotFound exception during default msvc tool initialization. Add additional tests.
@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 12, 2022

Updates:

  • Raise MSVCVersionNotFound exception instead of warning and returning empty/undefined dictionary from
    setup_env when the default msvc tools are requested and there are no msvc instances installed.

  • Raise MSVCVersionNotFound exception instead of warning and returning empty/undefined dictionary from msvc_find_valid_batch_script.

  • Exception text changed slightly from warnings for readibility

  • Added additional tests

Code path cases are shown below.

Test status summary:

  • Case 1: test\MSVC\no_msvc.py (added test\fixture\no_msvc\no_msvcs_sconstruct_tools.py)
  • Case 2: test\MSVC\no_msvc.py (remove print statement from test\fixture\no_msvc\no_msvcs_sconstruct.py)
  • Case 3: no test
  • Case 4: test\MSVC\msvc_badversion.py (requires at least one installed version of msvc)
  • Case 5: test\MSVC\no_msvc.py (added test\ficture\no_msvc\no_msvcs_sconstruct_version.py)
  • Case 6: no test - should never happen (see Case 2)

Case 1 - Build with non-msvc tools with no msvc installed instances:

scons: Reading SConscript files ...
Build: _build001 {'tools': ['mingw']}
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: _build001
gcc -o _build001\hello.o -c hello.c
gcc -o _build001\hello.exe _build001\hello.o
scons: done building targets.

Case 2 - Request default msvc with no msvc installed instances:

scons: Reading SConscript files ...
Build: _build001 {}
MSVCVersionNotFound: No versions of the MSVC compiler were found.
  Visual Studio C/C++ compilers may not be set correctly:
  ...
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 808:
    msvc_setup_env(env)
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 955:
    raise MSVCVersionNotFound(err_msg)

Case 3 - Path 1 in msvc_find_valid_batch_script (induced via code hack):

scons: Reading SConscript files ...
Build: _build001 {'MSVC_VERSION': '14.3'}
MSVCVersionNotFound: MSVC version 14.3 working host/target script was not found.
  Host = amd64, Target = amd64
  Visual Studio C/C++ compilers may not be set correctly:
  ...
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 976:
    d = msvc_find_valid_batch_script(env,version)
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 942:
    raise MSVCVersionNotFound(err_msg)

Case 4 - Path 2 in msvc_find_valid_batch_script:

Build: _build001 {'MSVC_VERSION': '12.9'}
MSVCVersionNotFound: MSVC version 12.9 was not found.
  Visual Studio C/C++ compilers may not be set correctly.
  Installed versions are: ['14.3', '14.2', '14.1', '14.1Exp', '14.0', '12.0', '11.0', '11.0Exp', '10.0', '10.0Exp', '8.0', '7.1', '7.0', '6.0']:
  ...
  File "S:\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 975:
    d = msvc_find_valid_batch_script(env,version)
  File "S:\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 941:
    raise MSVCVersionNotFound(err_msg)

Case 5 - Path 3 in msvc_find_valid_batch_script:

Build: _build001 {'MSVC_VERSION': '14.3'}
MSVCVersionNotFound: MSVC version 14.3 was not found.
  No versions of the MSVC compiler were found.
  Visual Studio C/C++ compilers may not be set correctly:
  ...
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 975:
    d = msvc_find_valid_batch_script(env,version)
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 941:
    raise MSVCVersionNotFound(err_msg)

Case 6 - Path 4 in msvc_find_valid_batch_script (should never happen - induced by code hack):

scons: Reading SConscript files ...
Build: _build001 {'MSVC_VERSION': '14.3'}
MSVCVersionNotFound: No versions of the MSVC compiler were found.
  Visual Studio C/C++ compilers may not be set correctly:
  ...
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 977:
    d = msvc_find_valid_batch_script(env,version)
  File "Z:\VMWare\SCons\scons-msvc-warnfix\scripts\..\SCons\Tool\MSCommon\vc.py", line 943:
    raise MSVCVersionNotFound(err_msg)

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 12, 2022

Returning an exception instead of warning now causes failures for the linux build(s). I'll look into soon...

@bdbaddog
Copy link
Contributor

@jcbrill - can you clarify what Paths 1-4 are for?

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 12, 2022

@bdbaddog Sure.

Annotated find_valid_batch_script fragment (just prior to exit):

    if not d:
        env['TARGET_ARCH']=req_target_platform
        installed_vcs = get_installed_vcs(env)
        if version_installed:
            # PATH 1 - version detected, batch file failed
            err_msg = "MSVC version {} working host/target script was not found.\n" \
                      "  Host = {}, Target = {}\n" \
                      "  Visual Studio C/C++ compilers may not be set correctly".format(
                          version, host_platform, target_platform
                      )
        elif version and installed_vcs:
            # PATH 2 - version is defined and there are installed vcs
            err_msg = "MSVC version {} was not found.\n" \
                      "  Visual Studio C/C++ compilers may not be set correctly.\n" \
                      "  Installed versions are: {}".format(version, installed_vcs)
        elif version:
            # PATH 3 - version is defined and there are no installed vcs
            err_msg = "MSVC version {} was not found.\n" \
                      "  No versions of the MSVC compiler were found.\n" \
                      "  Visual Studio C/C++ compilers may not be set correctly".format(version)
        else:
            # PATH 4 - version is undefined/None and/or there are no installed vcs
            #          if there are installed vcs, version should be defined
            #          if there are no installed vcs, empty default version should have failed in setup
            err_msg = "No versions of the MSVC compiler were found.\n" \
                      "  Visual Studio C/C++ compilers may not be set correctly"
        raise MSVCVersionNotFound(err_msg)

In english:

  • Path 1 is when an msvc version instance was detected but there was not a valid script (batch file found). The most likely cause is the there was a BatchFileExecution exception raised in script_env. In the current version, this likely could return an empty dictionary. I'm not sure how to write a test case for this as it is in the inner loop testing host/target combinations.
  • Path 2 is when the version is not None /empty and there is at least one installed msvc instances. In this case, the exception is raised and includes the list of installed versions. This could happen for a version number (e.g., 12.9) that cannot be found.
  • Path 3 is when the version is is not None/empty and there are no installed msvc instances. In this case, the exception raised indicates that there were not msvc instances found. This could happen for a version request (e.g., 14.3) on a computer without visual studio installed.
  • Path 4 is the catch all clause. This should not happen as the only way to get here is if the version is None/undefined. This should be caught in setup_env. The error message would be misleading if there actually were installed msvc instances.

The intent was to provide an error message that conveys as much information as possible about why an empty dictionary would have been returned which would have ultimately lead to cl.exe not being found.

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 12, 2022

The failures for the windows builds are almost all of the type version XX.X not found, (14.1 and 14.2 installed) for most of the msvs tests. That is, a version is hard-coded in the test that is not actually installed. Before, this would have issued a warning. Now it is an exception. The no_msvc test actually succeeded when it should have failed. Not sure why yet.,,

@mwichmann
Copy link
Collaborator

The failures for the windows builds are almost all of the type version XX.X not found, (14.1 and 14.2 installed) for most of the msvs tests. That is, a version is hard-coded in the test that is not actually installed. Before, this would have issued a warning. Now it is an exception.

Ah, yes, that's an old familiar pain point. Improve some code, no real code using it will ever have a problem, but the tests have hardcoded the exact behavior one is cleaning up, and so they have to be tweaked... been there many a time :-(

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 13, 2022

I need some guidance.

For the vm tests with only mingw installed and no msvc installations, I looked into Tool\mingw.py to figure out where it is looking for mingw. Since I build my own versions of mingw, I put a specific version folder in C:\mingw-w64\mingw-1110-v9-r0-64-win32-sjlj\mingw64 so it would be found via the function find_version_specific_mingw_paths in tool\mingw.py.

I could not understand why the default builds with no msvc installed instances were attempting to use msvc when there was a version of mingw-w64 installed. Forcing tools=['mingw'] worked fine.

Here's the rub: due to an omission in tool\mingw.py, the find_version_specific_mingw_paths is only used in the tool generate function and not in the tool exists function. During tool initialization, the exists function returns false since the find_version_specific_mingw_paths are not evaluated. This causes the compiler list to be empty in which case the first element is chosen which is msvc.

This explains why the following fails with a specific version in the C:\mingw-w64 \<SPECIFICVERSION>\mingw64 folder and no msvc instances fails with the msvc compiler:

env = Environment()

When the mingw code is adjusted to use the same paths in both generate and exists, the example above successfully compiles with the mingw compiler.

This appears to a bug. Should I open an issue and a PR or just the PR? Suggestions appreciated.

Aside: there is room for improvement with the order of the search paths, not hard-coding the windows system drive, and taking into account the platform bit size when looking for mingw/mingw-w64 folders (i.e., subfolder mingw32 vs mingw64).

@mwichmann
Copy link
Collaborator

mwichmann commented Apr 13, 2022

That tool initialization is poor is a known issue, subject of more than one issue and entries in "future generation blue-sky thinking" and so forth. The issue you're running into is that the two required functions aren't plumbed together - even if exists returns where it found the tool, nothing is done with that information, and the return is just used as a boolean (thus: it evaluates true) to decide whether to bother calling generate. Some tool modules, in fact, just return True and don't even bother (that's only supposed to happen if they're really always-true, as in, require no external component to check for). In a related problem, if you use non-default tools, exists isn't even called. Having exists and generate having to independently do the same job obviously leads to the well-known problem of code getting out of skew. One approach would be to factor that out, I think some tools do (put the finding logic in _find_mingw). Okay, enough rant from me...

Unless @bdbaddog disagrees, an issue that documents that mingw doesn't check the same way in exists as in generate seems useful, so we don't lose it.

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 13, 2022

The issue you're running into is that the two required functions aren't plumbed together - even if exists returns where it found the tool, nothing is done with that information, and the return is just used as a boolean (thus: it evaluates true) to decide whether to bother calling generate.

The root cause is that Mingw Exists is returning False when it should be returning True. No compilers in the win32 platform list are found so the list is intialized to the first element of the list which is 'msvc'.

When Mingw exists returns True, it is the only compiler found in the 'win32' list and is used as expected. Currently, mingw generate uses "mingw_paths + find_version_specific_mingw_paths" while exists only uses "mingw_paths". The installed tools are not found by exists so it does is filtered from the platform compiler tools list. When the platform tools list is empty, the first element is used. In this case, msvc which does not exist.

Ok. Will open an issue later today.

@bdbaddog
Copy link
Contributor

@jcbrill - Yes, please add an issue re mingw paths not consistently used between exists() and generate()

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 13, 2022

@mwichmann I have a history with the default selection of mingw tools. I tend to have multiple versions and builds of mingw in none of the places that scons used to look. When cygwin was added to the list it broke my builds as the cygwin tools were added to the paths and I was manually appending the local tools. Had to switch to prepending local tools to env path.

@mwichmann
Copy link
Collaborator

mwichmann commented Apr 14, 2022

The issue you're running into is that the two required functions aren't plumbed together - even if exists returns where it found the tool, nothing is done with that information, and the return is just used as a boolean (thus: it evaluates true) to decide whether to bother calling generate.

The root cause is that Mingw Exists is returning False when it should be returning True.

Right - I got that. I was saying that the two were out of skew - generate has some extra logic not in exists because duplication is fragile. You've addressed that nicely in your latest update.

@jcbrill
Copy link
Contributor Author

jcbrill commented Apr 14, 2022

Right - I got that.

It appears that I am the misbehaving tool :)

jcbrill added 3 commits April 15, 2022 07:26
…s not found. Remove exception for default msvc version and adjust test accordingly.
…ible combinations. Update exception message formatting.
@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 6, 2022

Apologies to @mwichmann and @bdbaddog for turning into a pumpkin for about two weeks. Life intervened in both expected and unexpected ways.

One question: Have we changed the default behavior for MSVC not found? This just goes into what the next release version is and also making sure we annotate the RELEASE.txt and CHANGES.txt with a big notice about such.

By suppressing the warning for the default tools and no MSVC_VERSION, it is possible that a build will fail (cl not found) without warning. The RELEASE.txt and CHANGES.txt should be fairly accurate with regard to this situation.

I am going to have to run some tests with the current master for not found behavior. I'm a little fuzzy at the moment concerning the prior code and how not found was handled. I just need some time reviewing the existing code.

Also @jcbrill - did you have more MSVC PR's queued up? (I wish we could get you to join the discord server to make such discussions quicker). The remaining items for the next release at this point are 1 ninja PR forthcoming, and if you had any other MSVC PR's queued up.

I don't have any that are ready to issue.

The following are on my short-term radar:

  1. MSVC script enhancements including user-defined arguments #4106 Adding support for MSVC_SCRIPT_ARGS (user-supplied supplementary arguments which for now would allow a toolset version, sdk version, spectre libraries, etc).
  2. Potentially move the vswhere methods and default paths to common.py from vc.py and add support for single json query.
  3. Separate/untangle the registry queries from the vswhere queries by version in vc.py which allows for runtime caching to be added to both.
  4. Add a warning/exception when "MSVC_UWP_APP" is ignored due to the MSVC_VERSION not supporting UWP apps. Not sure how this was allowed. I'm not a fan of silently ignoring a user request.
  5. Enhancements to the msvc cache filename processing (as discussed in the PR for the cache changes).

The first item should probably be done before the next release as it completes the "escape hatch" mechanisms for msvc batch files until first-class support for features can be added (if ever). It does require some validation: that the msvc version batch file actually supports arguments. The content of the user MSVC_SCRIPT_ARGS can't really be validated easily and will likely have to be assumed to be correct.

The rest don't necessarily have to be included in the next release as there is no urgency.

The PR for the preview version is woefully out-of-date and will take a non-trivial amount of work to revive.

One or two of the msvc bug scrub items could probably be closed via adding documentation. Figuring out where would be another kettle of fish.

(I wish we could get you to join the discord server to make such discussions quicker)

Understood. Will (likely) join soon...

@bdbaddog
Copy link
Contributor

bdbaddog commented Jun 6, 2022

@jcbrill - Agreed that holding release for item 1 above is worthwhile.

As far as validating the contents thereof, I think we can punt on that, and just file an enhancement issue once merged so we don't drop that. There may be reasonable ways to do something useful with validation, but certainly that shouldn't hold up progress. (since use would most likely be by "advanced" users?)

Previous msvc logic would basically leave env['ENV'] without updates to find/run msvc if no version is found, yielding the "cl.exe not found".

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 6, 2022

As far as validating the contents thereof, I think we can punt on that, and just file an enhancement issue once merged so we don't drop that. There may be reasonable ways to do something useful with validation, but certainly that shouldn't hold up progress. (since use would most likely be by "advanced" users?)

I agree.

The intent with the "escape hatch" mechanisms was to provide one way to get around any limitations in the current implementation and not necessarily the best way. Basically, it is way to prevent a user getting "stuck" until something better comes along.

Previous msvc logic would basically leave env['ENV'] without updates to find/run msvc if no version is found, yielding the "cl.exe not found".

That was my immediate recollection as well.

The current difference will be for the default tool list and no MSVC_VERSION specification: no warning issued and "cl.exe not found". The prior version would issue a warning for the default tools configuration.

@bdbaddog
Copy link
Contributor

bdbaddog commented Jun 6, 2022

@jcbrill - re pumpkin. No worries, life happens. your continued contributions are very welcome and worth waiting for! :)

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 6, 2022

Off topic for this thread: the following msvc-bug-scrub items likely should be tagged as "enhancement": #4106, #4048, #3664, #4149. I suppose the last two could be controversial. For the current architecture, it is an enhancement.

Not sure if all remaining bug scrub items can make it into next release or not. The remaining items are fairly old so there is not really any apparent urgency.

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 7, 2022

@bdbaddog and @mwichmann Please review at your convenience. Illustrations of old and new behavior. Comments and questions always welcome.

Presented below are the results from 4 experimental configurations with 8 scons invocations (methods) for each experiment for the master and the warnfix PR. The results are presented below in a table for the master, a table for the warnfix PR, a table with the primary differences, and some notes.

Wordsmithing the MSVC_NOTFOUND_POLICY documentation is going to be challenging as there is an asymmetry in the behavior of an MSVC_VERSION specification based on software installed and the specified tool list.

For the test methods with msvc installed, the default builds will succeed and the version specific builds will fail (9.0Exp is not installed). This was by design.

Note: I could not figure out how to prevent word-wrap inside the tables. They are easier to interpret without word-wrap. C'est la vie.

Experiment Configuration

Experiment MSVC MinGW Comment
E1 (CL=0, GCC=0) MSVC not installed MinGW not installed no compilers available
E2 (CL=0, GCC=1) MSVC not installed MinGW installed gcc available
E3 (CL=1, GCC=0) MSVC 14.3 installed, 9.0Exp not installed MinGW not installed default cl available
E4 (CL=1, GCC=1) MSVC 14.3 installed, 9.0Exp not installed MinGW installed default cl and gcc available

SCons Environment Configuration

Method MSVC_VERSION Tools Comment
M1 n/a n/a default tools (implicit)
M2 n/a default default tools (explicit)
M3 n/a mingw MinGW tools
M4 n/a msvc, mslink MSVC tools
M5 9.0Exp n/a MSVC_VERSION and default tools (implicit)
M6 9.0Exp default MSVC_VERSION and default tools (explicit)
M7 9.0Exp mingw MSVC_VERSION and mingw tools
M8 9.0Exp msvc, mslink MSVC_VERSION and msvc tools

Master

Method MSVC_VERSION Tools E1 (CL=0, GCC=0) E2 (CL=0, GCC=1) E3 (CL=1, GCC=0) E4 (CL=1, GCC=1)
M1 n/a n/a 2 Warn, cl fail [1] gcc success cl success cl success
M2 n/a default 2 Warn, cl fail [2] gcc success cl success cl success
M3 n/a mingw 1 Warn, gcc fail [3] gcc success gcc fail gcc success
M4 n/a msvc, mslink 2 Warn, cl fail 1 Warn, cl fail cl success cl success
M5 9.0Exp n/a 5 Warn, cl fail gcc success [5] 4 Warn, cl fail 4 Warn, cl fail
M6 9.0Exp default 5 Warn, cl fail gcc success [6] 4 Warn, cl fail 4 Warn, cl fail
M7 9.0Exp mingw 1 Warn, gcc fail [4] gcc success gcc fail gcc success
M8 9.0Exp msvc, mslink 5 Warn, cl fail 4 Warn, cl fail 4 Warn, cl fail 4 Warn, gcc fail

Warnfix PR (MSVC_NOTFOUND_POLICY=Warning)

Method MSVC_VERSION Tools E1 (CL=0, GCC=0) E2 (CL=0, GCC=1) E3 (CL=1, GCC=0) E4 (CL=1, GCC=1)
M1 n/a n/a cl fail [1] gcc success cl success cl success
M2 n/a default cl fail [2] gcc success cl success cl success
M3 n/a mingw gcc fail [3] gcc success gcc fail gcc success
M4 n/a msvc, mslink 2 Warn, cl fail 2 Warn, cl fail cl success cl success
M5 9.0Exp n/a 1 Warn, cl fail 1 Warn, cl fail [5] 1 Warn, cl fail 1 Warn, cl fail
M6 9.0Exp default 1 Warn, cl fail 1 Warn, cl fail [6] 1 Warn, cl fail 1 Warn, cl fail
M7 9.0Exp mingw gcc fail [4] gcc success gcc fail gcc success
M8 9.0Exp msvc, mslink 1 Warn, cl fail 1 Warn, cl fail 1 Warn, cl fail 1 Warn, cl fail

Differences between Master and Warnfix PR

Note Method MSVC_VERSION Tools Exp Master Warnfix PR Comment
1 M1 n/a n/a E1 2 Warn, cl fail cl fail Msvc warning suppressed when no msvc versions detected
2 M2 n/a default E1 2 Warn, cl fail cl fail Msvc warning suppressed when no msvc versions detected
3 M3 n/a mingw E1 1 Warn, gcc fail gcc fail Msvc warning suppressed when no msvc versions detected
4 M7 9.0Exp mingw E1 1 Warn, gcc fail gcc fail Msvc warning suppressed when no msvc versions detected
5 M5 9.0Exp n/a E2 gcc success 1 Warn, cl fail MSVC_VERSION causes the msvc tools to be used
6 M6 9.0Exp default E2 gcc success 1 Warn, cl fail MSVC_VERSION causes the msvc tools to be used

For [1] and [2] (no compilers installed, force using msvc): the msvc warning is suppressed for the default tools. This can lead to build failures without a warning if the environment is used to build a program or library.

For [3] and [4] (no compilers installed, using gcc): the msvc warning is suppressed for non-msvc tools.

For [5] and [6] (no msvc installed, gcc installed): there was a change in behavior from the current master to the warnfix PR when MSVC_VERSION is defined, no versions of MSVC are detected, and the default tool list is used. The msvc tools are forced into the list when MSVC_VERSION is defined.

SConstruct (8 test cases):

method_dict = {
    1: ('NOVERSION_NONE',    {} ),
    2: ('NOVERSION_DEFAULT', {'tools': ['default']} ), 
    3: ('NOVERSION_MINGW',   {'tools': ['mingw']} ), 
    4: ('NOVERSION_MSVC',    {'tools': ['msvc', 'mslink']} ), 
    5: ('VERSION_NONE',      {'MSVC_VERSION': '9.0Exp'} ), 
    6: ('VERSION_DEFAULT',   {'MSVC_VERSION': '9.0Exp', 'tools': ['default']} ), 
    7: ('VERSION_MINGW',     {'MSVC_VERSION': '9.0Exp', 'tools': ['mingw']} ), 
    8: ('VERSION_MSVC',      {'MSVC_VERSION': '9.0Exp', 'tools': ['msvc', 'mslink']} ), 
}

AddOption('--method', action='store', dest='method_nbr', default=1, type=int, help="test method number")
method_nbr = GetOption('method_nbr')
if not (1 <= method_nbr <= len(method_dict)):
    raise RuntimeError('unsupported test method number ({})'.format(method_nbr))

runlabel, envdict = method_dict[method_nbr]
print('Method {}: {} ({})'.format(method_nbr, runlabel, envdict))

env_list = []

def make_environment(kwargs):
    global env_list
    build_n = len(env_list) + 1
    build = '_build{:03d}'.format(build_n)
    print('Build:', build, kwargs)
    VariantDir(build, '.', duplicate=0)
    env=Environment(**kwargs)
    env.Program(build + '/hello', [build + '/hello.c'])
    env_list.append(env)
    # print(env.Dump())
    return env

make_environment(envdict)

@bdbaddog
Copy link
Contributor

bdbaddog commented Jun 7, 2022

Off topic for this thread: the following msvc-bug-scrub items likely should be tagged as "enhancement": #4106, #4048, #3664, #4149. I suppose the last two could be controversial. For the current architecture, it is an enhancement.

Not sure if all remaining bug scrub items can make it into next release or not. The remaining items are fairly old so there is not really any apparent urgency.

I'd say all but #3664 are enhancements. And perhaps that one too, I've added a comment there with what I hope is a somewhat accurate recap and reasoned way forward? Of course allowing the user to specify the script arguments is a workaround to adding another MSVC_ envvar. (and adds more flexibility, but is more complicated than adding MSVC_TOOLSET (or other named var)..

@mwichmann
Copy link
Collaborator

Off topic for this thread: the following msvc-bug-scrub items likely should be tagged as "enhancement": #4106, #4048, #3664, #4149. I suppose the last two could be controversial. For the current architecture, it is an enhancement.

Updated (one has discussion pending)

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 7, 2022

I'd say all but #3664 are enhancements. And perhaps that one too, I've added a comment there with what I hope is a somewhat accurate recap and reasoned way forward? Of course allowing the user to specify the script arguments is a workaround to adding another MSVC_ envvar. (and adds more flexibility, but is more complicated than adding MSVC_TOOLSET (or other named var)..

I added my 2cents in the other thread before seeing this. I would say you have captured the situation concisely.

@bdbaddog
Copy link
Contributor

bdbaddog commented Jun 7, 2022

Comment 100.. Just because.. ;)

Re

For [1] and [2] (no compilers installed, force using msvc): the msvc warning is suppressed for the default tools. This can lead to build failures without a warning if the environment is used to build a program or library.

So for both those cases, previously we'd get a no msvc warning, when none was explicitly requested?
So in effect, previous behavior was wrong? But that yields env['CC']='cl.exe' ? (which is what would have always happened?)

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 7, 2022

So for both those cases, previously we'd get a no msvc warning, when none was explicitly requested?

Yes. Previously (master), we would get a warning because the msvc compiler was "force set" as the default compiler even though there were no detected instances. When the default tools initialized, there was a warning that was triggered when setup_env_once was invoked. This warning has been removed in the current PR.

So in effect, previous behavior was wrong? But that yields env['CC']='cl.exe' ? (which is what would have always happened?)

Wrong is probably too strong.

The tool initialization always set a default compiler even if it does not exist (which I'm guessing probably makes the implementation simpler/straightforward as there is always a compiler configured).

There is a fundamental problem with the default environment that when the tools are setup/initialized it is too early to know if and/or how they might actually be used if at all. Sort of a "closing the gate after the horse has left the barn problem".

There aren't too many options here:

  1. the old way was to issue a warning even if it is innocuous which is safe but possibly annoying with no recourse other than installing a c compiler.
  2. the new way is to suppress the warning at the expense of a build failure later because there are no c compilers installed.

Someone will be annoyed either way.

There are legitimate scons uses that don't require a c compiler, so suppressing the warning makes sense.

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 9, 2022

What happens if the user runs the MSVC developer shell and does
env=Environment(ENV=os.environ)
Will this still work/not issue warnings for the defaulted MSVC_VERSION case?
(a non-trivial amount of users/projects do this, even though (in general) auto-detection would be better IMHO)

The testing around this request revealed that a minor tweak to the implementation was required. Unfortunately, this means that I will have to revisit the previous experiments to make sure that they still work as expected which is fairly laborious. And so it goes...

Setting the command-line environment via the msvc batch files and then using SCons via Environment(ENV=os.environ) is a really bad idea. At a minimum, Environment(ENV=os.environ, MSVC_USE_SCRIPT=None) should be used.

The issue is illustrated below using a VS2022 Preview command-line configuration that targets ARM64. The executable is built from the command-line prior to calling SCons to verify that the ARM64 executable is built (windows error indicating invalid architecture). Any executable that runs successfully under windows is built for the wrong architecture.

When using Environment(ENV=os.environ), the command-line paths are added as expected. However, the default msvc tool paths are promoted/prepended during setup leaving the default msvc tools targeting amd64 at the fronts of the environment lists rather than ARM64.

Experiment Configuration

Experiment MSVC MinGW Comment
E1 (CL=0, GCC=0) MSVC 14.3 Preview installed MinGW not installed no compilers detected
E2 (CL=0, GCC=1) MSVC 14.3 Preview installed MinGW installed gcc detected
E3 (CL=1) MSVC 14.3 Release and Preview installed N/A default cl 14.3 Release detected

SCons Environment Configuration

Method Environment
M1 Environment(ENV=os.environ) # cmdline 2022 Preview, amd64_arm64
M2 Environment(ENV=os.environ, MSVC_USE_SCRIPT=None) # cmdline 2022 Preview, amd64_arm64
M3 Environment(MSVC_USE_SCRIPT='<2022 Preview>', MSVC_USE_SCRIPT_ARGS='amd64_arm64')
M4 Environment(MSVC_USE_SETTINGS={<2022 Preview> amd64_arm64})
M5 Environment(MSVC_VERSION='14.3', ENV=os.environ) # cmdline 2022 Preview, amd64_arm64
M6 Environment(MSVC_VERSION='14.3', ENV=os.environ, MSVC_USE_SCRIPT=None) # cmdline 2022 Preview, amd64_arm64
M7 Environment(MSVC_VERSION='14.3', MSVC_USE_SCRIPT='<2022 Preview>', MSVC_USE_SCRIPT_ARGS='amd64_arm64')
M8 Environment(MSVC_VERSION='14.3', MSVC_USE_SETTINGS={<2022 Preview amd64_arm64>})

Note

Some of the M2 and M6 experiments issue the following warning: MSVC_USE_SCRIPT set to False, assuming environment set correctly.

This warning is NOT included in the tables below.

Master

Method E1 (CL=0, GCC=0) E2 (CL=0, GCC=1) E3 (CL=1)
M1 2 Warn, cl ARM64 gcc x86/amd64 [1] cl amd64 [2]
M2 2 Warn, cl ARM64 gcc x86/amd64 [1] cl ARM64
M3 2 Warn, cl fail [3] gcc x86/amd64 [1] cl ARM64
M4 2 Warn, cl fail [3] gcc x86/amd64 [1] cl ARM64
M5 5 Warn, cl ARM64 gcc x86/amd64 [1] cl amd64 [2]
M6 1 Warn, cl ARM64 gcc x86/amd64 [1] cl ARM64
M7 1 Warn, cl ARM64 gcc x86/amd64 [1] cl ARM64
M8 1 Warn, cl ARM64 gcc x86/amd64 [1] cl ARM64

Warnfix PR (MSVC_NOTFOUND_POLICY=Warning)

Method E1 (CL=0, GCC=0) E2 (CL=0, GCC=1) E3 (CL=1)
M1 cl ARM64 gcc x86/amd64 [1] cl amd64 [2]
M2 cl ARM64 cl ARM64 cl ARM64
M3 cl fail [3] cl fail [3] cl ARM64
M4 cl fail [3] cl fail [3] cl ARM64
M5 1 Warn, cl ARM64 1 Warn, cl ARM64 cl amd64 [2]
M6 cl ARM64 cl ARM64 cl ARM64
M7 cl ARM64 cl ARM64 cl ARM64
M8 cl ARM64 cl ARM64 cl ARM64

Table Footnotes

  1. The command-line environment was configured to build using VS2022 Preview targeting ARM64.
    With no msvc instances detected, the gcc build targeting x86/amd64 succeeds (not sure which).
  2. The command-line environment was configured to build using VS2022 Preview targeting ARM64.
    Using the default tools (14.3 Release), the cl build targeting amd64 succeeds.
  3. With no msvc instances detected, the msvc setup bails out early (no valid MSVC_VERSION).
    Speficifying MSVC_VERSION will result in successful builds.

General Comments

  • Using Environment(ENV=os.environ) without MSVC_USE_SCRIPT=None is a really bad idea.
  • When using MSVC_USE_SCRIPT=None, MSVC_USE_SCRIPT=<script>, or MSVC_USE_SETTINGS={dict} it is probably a good idea to define a MSVC_VERSION especially when there are no detectable msvc instances.

@bdbaddog
Copy link
Contributor

bdbaddog commented Jun 9, 2022

Re:
Using Environment(ENV=os.environ) without MSVC_USE_SCRIPT=None is a really bad idea.

Sadly I've seen a LOT of projects building with SCons recommend this.
(And more than few stack overflow answers to can't find msvc recommend this)
That said, I'd bet none of them are (yet) using VS2022..
I'd guess(?) that this is only a problem if you have arm(*) installed, and/or are on newer version of MSVC?

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 9, 2022

I'd guess(?) that this is only a problem if you have arm(*) installed, and/or are on newer version of MSVC?

It could be a problem whenever the command-line configured target is different from the default tools configured target. Going back to when 64-bit support was added in VS2005(?). The default msvc tools tend to default to the host architecture.

Cross-compiling would be an example:

  • 64-bit windows, the command-line environment targeting x86, the default tools target amd64
  • 32-bit windows, the command-line environment targeting amd64, the default tools target x86.

Arm/ARM64 just add more combinations.

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 9, 2022

That said, I'd bet none of them are (yet) using VS2022

VS2022 is the only Preview installer that I have on hand.

For the recent tests, I wanted to use a command-line version of msvc that is not detected by SCons. That made it easier when going through the paths to see what was going on and which version was configured.

@bdbaddog
Copy link
Contributor

The os.environ() usage is being suggested even for supported MSVC. (As seen in the wild).
So perhaps some rudimentary testing of that would be viable?

And/or document the change needed to make that work (as you said MSVC_USE_SCRIPT=None)?

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 10, 2022

And/or document the change needed to make that work (as you said MSVC_USE_SCRIPT=None)?

It probably would be a good idea to gather examples of the existing options available and describe why one might choose one method over another: MSVC_USE_SCRIPT=None, MSVC_USE_SCRIPT/MSVC_USE_SCRIPT_ARGS, when MSVC_VERSION should be used, etc.

As usual, there are a few different things going on that makes it more complicated.

Using Environment(ENV=environ) has no notion of MSVC_VERSION or TARGET_ARCH. Without MSVC_VERSION, the default tools (highest msvc version installed) are used.

One implication of this is that if the version of msvc cannot be detected and there are no other msvc versions installed, if any other c compiler is installed and detected it will be used (see M1/E2 above).

I believe that MSVC_VERSION is used in some of the tools for determining tool options/formats (possibly really old versions of msvc circa VS2005?).

Even if there is only one version of msvc installed and that version is detected by scons, there could still be a discrepancy between the target arch in the environment and the target arch for the "default" msvc tool (as demonstrated above).

Issues are more likely to arise when there are more than one version of msvc installed even if all versions of msvc are detected. As the gap between the environment version and the default tools version widens, the possibility of an undesirable outcome increases.

For example, VS2019 and VS2013 are installed. If the command-line is configured for VS2013 and the default tools are VS2019, even if the target architectures are the same there could be issues with msvc runtime dependencies depending on what and how something is being built. For example, building a DLL could inadvertently be using ucrt instead of msvcr120.

Keeping in mind that MSVC_USE_SCRIPT_ARGS was added not that long ago (and not made it into a formal release), I'm not sure why os.environ would be more attractive than using MSVC_USE_SCRIPT and MSVC_USE_SCRIPT_ARGS. Although an MSVC_VERSION would be necessary if the installed version of msvc was not detectable and the only version installed.

Sample output illustrating potential issue

C:\HOST-ENVIRONMENT-PATH-BEG was added to the system path prior to running the msvc batch file, ran the msvc batch file, and then added C:\HOST-ENVIRONMENT-PATH-END to the system path to bracket the paths that the command-line environment set prior to running SCons. Msvc sometimes adds paths the end of the path list so these are not shown below (they were present just not printed).

Below is the difference in constructed ENV paths and the cl.exe path for os.environ with and without MSVC_USE_SCRIPT=None. Manually indented for illustration purposes.

Command-line msvc root (14.3 Preview): C:\Software\MSVS-2022-143-Com-Pre targeting ARM64
Default msvc root (14.3): C:\Software\MSVS-2022-143-Com targeting amd64

This is the path through the begin marker and the cl.exe found for M1/E3 (Environment(ENV=environ)) which uses VS 2022 14.3 targeting amd64:

PATH C:\Software\MSVS-2022-143-Com\VC\Tools\MSVC\14.32.31326\bin\HostX64\x64
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\VC\VCPackages
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\CommonExtensions\Microsoft\TestWindow
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer
PATH C:\Software\MSVS-2022-143-Com\MSBuild\Current\bin\Roslyn
PATH C:\Software\MSVS-2022-143-Com\Team Tools\Performance Tools\x64
PATH C:\Software\MSVS-2022-143-Com\Team Tools\Performance Tools
PATH C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64
PATH C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\
PATH C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\
PATH C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\\x64
PATH C:\Program Files (x86)\Windows Kits\10\bin\\x64
PATH C:\Software\MSVS-2022-143-Com\\MSBuild\Current\Bin\amd64
PATH C:\Windows\Microsoft.NET\Framework64\v4.0.30319
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\
PATH C:\Software\MSVS-2022-143-Com\Common7\Tools\
PATH C:\Windows\System32
PATH C:\Windows\System32\Wbem
PATH C:\Windows\System32\WindowsPowerShell\v1.0
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja
PATH C:\Software\MSVS-2022-143-Com\Common7\IDE\VC\Linux\bin\ConnectionManagerExe
PATH C:\HOST-ENVIRONMENT-PATH-END
PATH     C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\ARM64
PATH     C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\x64
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\VC\VCPackages
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\CommonExtensions\Microsoft\TestWindow
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer
PATH     C:\Software\MSVS-2022-143-Com-Pre\MSBuild\Current\bin\Roslyn
PATH     C:\Software\MSVS-2022-143-Com-Pre\Team Tools\Performance Tools
PATH     C:\Program Files (x86)\HTML Help Workshop
PATH     C:\Software\MSVS-2022-143-Com-Pre\\MSBuild\Current\Bin\amd64
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\Tools\
PATH C:\HOST-ENVIRONMENT-PATH-BEG

CL.EXE * C:\Software\MSVS-2022-143-Com\VC\Tools\MSVC\14.32.31326\bin\HostX64\x64\cl.exe
CL.EXE   C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\ARM64\cl.exe
CL.EXE   C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\x64\cl.exe

This is the path through the begin marker and the cl.exe found for M2/E3 (Environment(ENV=environ, MSVC_USE_SCRIPT=None)) which uses VS2022 14.3 Preview targeting ARM64:

PATH C:\HOST-ENVIRONMENT-PATH-END
PATH     C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\ARM64
PATH     C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\x64
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\VC\VCPackages
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\CommonExtensions\Microsoft\TestWindow
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer
PATH     C:\Software\MSVS-2022-143-Com-Pre\MSBuild\Current\bin\Roslyn
PATH     C:\Software\MSVS-2022-143-Com-Pre\Team Tools\Performance Tools
PATH     C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\
PATH     C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\
PATH     C:\Program Files (x86)\HTML Help Workshop
PATH     C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\\x64
PATH     C:\Program Files (x86)\Windows Kits\10\bin\\x64
PATH     C:\Software\MSVS-2022-143-Com-Pre\\MSBuild\Current\Bin\amd64
PATH     C:\Windows\Microsoft.NET\Framework64\v4.0.30319
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\IDE\
PATH     C:\Software\MSVS-2022-143-Com-Pre\Common7\Tools\
PATH C:\HOST-ENVIRONMENT-PATH-BEG

CL.EXE * C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\ARM64\cl.exe
CL.EXE   C:\Software\MSVS-2022-143-Com-Pre\VC\Tools\MSVC\14.33.31424\bin\HostX64\x64\cl.exe

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 10, 2022

And/or document the change needed to make that work (as you said MSVC_USE_SCRIPT=None)?

MSVC_USE_SCRIPT=None always issues a warning.

I am not wild about a documented feature that always issues a warning without a straightforward way to disable the warning (there may be such a way and I am unaware of said method).

There are two places where an attempt to configure the msvc environment is made but checking for cl.exe is bypassed.

The manner in which the existing code is written (annotated):

...
    use_script, use_settings = get_use_script_use_settings(env)
    if SCons.Util.is_String(use_script):
        use_script = use_script.strip()
        if not os.path.exists(use_script):
            raise MSVCScriptNotFound('Script specified by MSVC_USE_SCRIPT not found: "{}"'.format(use_script))
        args = env.subst('$MSVC_USE_SCRIPT_ARGS')
        debug('use_script 1 %s %s', repr(use_script), repr(args))
        d = script_env(use_script, args)
    elif use_script:
        d = msvc_find_valid_batch_script(env,version)
        debug('use_script 2 %s', d)
        ### POSSIBLY SOMETHING SIMILAR COULD BE DONE HERE AS WELL ###
        if not d:
            return d
    elif use_settings is not None:
        if not SCons.Util.is_Dict(use_settings):
            error_msg = 'MSVC_USE_SETTINGS type error: expected a dictionary, found {}'.format(type(use_settings).__name__)
            raise MSVCUseSettingsError(error_msg)
        d = use_settings
        debug('use_settings %s', d)
    else:
        ### MSVC_USE_SCRIPT=None DOCUMENTED AND ALWAYS ISSUES WARNING ###
        debug('MSVC_USE_SCRIPT set to False')
        warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
                   "set correctly."
        SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
        return None

    for k, v in d.items():
        env.PrependENVPath(k, v, delete_existing=True)
        debug("env['ENV']['%s'] = %s", k, env['ENV'][k])

    # final check to issue a warning if the compiler is not present
    if not find_program_path(env, 'cl'):
        debug("did not find %s", _CL_EXE_NAME)
        if CONFIG_CACHE:
            propose = "SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {} if out of date.".format(CONFIG_CACHE)
        else:
            propose = "It may need to be installed separately with Visual Studio."
        warn_msg = "Could not find MSVC compiler 'cl'. {}".format(propose)
        SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
...

could possibly be changed to:

...
    else:
        debug('MSVC_USE_SCRIPT set to False')
        d = {}
...

Which would "fall-through":

  • No items would be prepended to the path as the dictionary is empty
  • A warning would be issued if cl.exe is not on the path

These would seem like a better use of a warning: replace a warning for "this feature was employed" to "could not find the compiler".

Something similar could be done with the "use_script" case as well.

My 2cents.

Postscript: Probably need a "cache used" boolean variable so that the cl.exe check only issues the cache portion of the message if the cache was used in the relevant code path.

@mwichmann
Copy link
Collaborator

If I don't misremember, the msvc stuff uses the SCons warnings framework, which can be configured on/off/etc. If that was the question.

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 10, 2022

If I don't misremember, the msvc stuff uses the SCons warnings framework, which can be configured on/off/etc. If that was the question.

I am confident that you are correct.

Documentation fragment (emphasis added):

MSVC_USE_SCRIPT
Use a batch script to set up the Microsoft Visual C++ compiler.

If set to the name of a Visual Studio .bat file (e.g. vcvars.bat), SCons will run that batch file instead of the auto-detected one, and extract the relevant variables from the result (typically %INCLUDE%, %LIB%, and %PATH%) for supplying to the build. This can be useful to force the use of a compiler version that SCons does not detect.

Setting $MSVC_USE_SCRIPT to None bypasses the Visual Studio autodetection entirely; use this if you are running SCons in a Visual Studio cmd window and importing the shell's environment variables - that is, if you are sure everything is set correctly already and you don't want SCons to change anything.

$MSVC_USE_SCRIPT overrides $MSVC_VERSION and $TARGET_ARCH.

If nothing else, it should probably be mentioned in the documentation that a warning will be issued and how to turn it off.

@bdbaddog
Copy link
Contributor

@jcbrill @mwichmann - Any opposition to merging this PR as is, and then we can create another PR to polish up these final details?

@jcbrill
Copy link
Contributor Author

jcbrill commented Jun 11, 2022

Any opposition to merging this PR as is, and then we can create another PR to polish up these final details?

Fine with me. I wasn't planning on doing anything else for this PR after my last commit this morning unless there were any requests.

@bdbaddog bdbaddog merged commit b28c8bc into SCons:master Jun 11, 2022
@jcbrill jcbrill deleted the jbrill-msvc-warnfix branch June 11, 2022 22:05
@mwichmann mwichmann added this to the 4.4 milestone Jun 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MSVC Microsoft Visual C++ Support Op Sys: Windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

scons still emits warnings about missing MSVC compiler

3 participants