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

MSVC script enhancements including user-defined arguments #4106

Closed
jcbrill opened this issue Feb 26, 2022 · 6 comments · Fixed by #4174
Closed

MSVC script enhancements including user-defined arguments #4106

jcbrill opened this issue Feb 26, 2022 · 6 comments · Fixed by #4174
Labels
enhancement MSVC Microsoft Visual C++ Support

Comments

@jcbrill
Copy link
Contributor

jcbrill commented Feb 26, 2022

With the recent PR proposing adding arguments to user-defined script/batch files (MSVC_USE_SCRIPT can pass in args #4102), perhaps it is worthwhile to revive the discussion had earlier in PR #4063.

There are three potential enhancements to msvc usage that would enhance the user experience:

  1. Passing user-defined arguments to the user-defined script specified via MSVC_USE_SCRIPT,
  2. Passing user-defined arguments when using the normal SCons msvc detection,
  3. Passing a user-defined environment (i.e., ENV-like) dictionary to be used in lieu of SCons msvc detection or user-specified script.

In the interest of full disclosure: the author also has a code branch ready implementing Items 1 and 3 above but has not updated the requisite documentation yet. Implementation of Item 2 in the current SCons code base is not as straightforward as Items 1 and 3 and has been deferred to a later date.

The first two items make available to an SCons end-user all of the msvc batch file options available to command-line users. The first two items effectively provide a "universal escape hatch" which also reduces the burden on SCons development to "catch-up" with currently unsupported features and/or any new shiny features that may be added to msvc batch files in the future.

The third item is a middle ground between the all (SCons msvc detection via restricted system execution environment) or nothing (user-populated environment) currently offered. While the utility may not be readily apparent, the reader is encouraged to keep an open mind before rushing to a snap judgment. Additional support material will be provided in future posts.

The user-provided content for Item 1 (script arguments) and Item 2 (pass-through script arguments) are not likely to be the same as "native" features are added to SCons. In the current SCons implementation, the store/UWP argument is available via the MSVC_UWP_APP variable while a user-defined script would need to use the "store" argument. If toolset support were added to SCons, the script argument(s) would still need the toolset specification while the pass-through argument(s) would not.

It would likely be best if there are two distinct environment variables for user-defined script arguments and user-defined pass-through arguments:

  • MSVC_USE_SCRIPT_ARGS for user-defined script arguments
  • MSVC_ADD_ARGS for pass-through arguments (or possibly MSVC_PASS_ARGS)

Item 1 - MSVC_USE_SCRIPT_ARGS rationale:

  • MSVC_USE_SCRIPT_ARGS is only used when MSVC_USE_SCRIPT is defined.
  • MSVC_USE_SCRIPT_ARGS would follow MSVC_USE_SCRIPT in the documentation.
  • the usage restriction is fairly apparent by the name.
  • allowing a (scalar) string or list of strings is a useful user-facing enhancement.

Item 2 - MSVC_ADD_ARGS or MSVC_PASS_ARGS notes:

  • This is a little trickier to find a decent variable name. The trade-off is finding a variable name that is both descriptive and cannot be easily confused with the name of the user-defined script arguments variable.

Item 3 - ENV-like dictionary notes:

  • There is a wide gap between using SCons msvc detection and bypassing detection altogether: it is tantamount to an all or nothing proposition.
  • Passing in a user-defined ENV-like dictionary allows for:
    • alternate user-side msvc detection which could overcome any limitations imposed by the current restricted SCons system execution environment,
    • alternate user-side msvc detection which can provide features not available in the current SCons implementation (e.g., selection of msvc preview versions, selection by msvc toolset, selection by msvc buildtools, selection by msvc runtime, alternate msvc selection algorithms, etc.),
    • user-side msvc environment caching outside of SCons, and
    • provides a "testbed" hook for rapid prototyping new features outside the SCons code base.
  • Additional rationale and/or examples demonstrating the utility will have to be provided in future posts.

The relevant posts from closed PR #4063 are quoted here for convenience (note that the proposed implementation details have changed since originally posted):

Originally posted by @jcbrill in #4063 (comment)

A bit off topic: an enhancement that I was planning on proposing once this was resolved is the addition of a user specified script argument: MSVC_USE_SCRIPT_ARG to be used in conjunction with MSVC_USE_SCRIPT. This would allow any flags recognized by the msvc batch files to be passed along with the script name.

For example, this would allow the following which currently can't be achieved directly in a SConstruct/SConscript file without resorting to a user-defined batch file (VS2022 Preview, amd64 target, toolset 14.2, sdk 10.0.19041.0):

use_version    = '14.3'
use_script     = 'c:\\software\\msvs143bt-pre\\VC\\Auxiliary\\Build\\vcvarsall.bat'
use_script_arg = 'amd64 --vcvars_ver=14.2 10.0.19041.0'

env = Environment(MSVC_VERSION = use_version, MSVC_USE_SCRIPT = use_script, MSVC_USE_SCRIPT_ARG = use_script_arg)

If something like this were added, there would be no good way to validate the user provided script argument other than call subprocess. In this case it could be harder to distinguish between a user error and a system error.

Unfortunately, current msvc logic will not pick up batch file errors correctly (unless cl.exe is not added to the path). There is room for improvement in this area.

Originally posted by @jcbrill in #4063 (comment)

Further off-topic: If a user script argument were allowed and an overloaded version when MSVC_USE_SCRIPT=None allowing a dictionary to be passed, it is possible in user space to unify/resolve most of the outstanding msvc issues/requests (preview, toolsets, components, etc).

Working SConstruct fragments via script argument enhancements:

from vsdetect import scons_msvc_byinstance as scons_msvc

# SCons runs batch file: MSVC_USE_SCRIPT (string) and MSVC_USE_SCRIPT_ARG (string)
env = Environment(**scons_msvc(MSVC_VERSION='14.3', MSVC_PREVIEW=True, MSVC_COMPONENT='BuildTools', MSVC_TOOLSET='14.2', TARGET_ARCH='amd64', MSVC_ADD_ARG='10.0.19041.0', run_script=False))

# user runs batch file: MSVC_USE_SCRIPT (None) and MSVC_USE_SCRIPT_ARG (dictionary)
env = Environment(**scons_msvc(MSVC_VERSION='14.3', MSVC_PREVIEW=True, MSVC_COMPONENT='BuildTools', MSVC_TOOLSET='14.2', TARGET_ARCH='amd64', MSVC_ADD_ARG='10.0.19041.0', run_script=True))

# lookup by c runtime
env = Environment(**scons_msvc(MSVC_RUNTIME='140', MSVC_PREVIEW=True, MSVC_COMPONENT='BuildTools', MSVC_TOOLSET='14.2', TARGET_ARCH='amd64', MSVC_ADD_ARG='10.0.19041.0', run_script=True))

# lookup by toolset
env = Environment(**scons_msvc(MSVC_TOOLSET='14.2', MSVC_PREVIEW=True, MSVC_COMPONENT='BuildTools', TARGET_ARCH='amd64', MSVC_ADD_ARG='10.0.19041.0', run_script=True))

This would also allow user-side caching if the overloaded dictionary support were added.

Originally posted by @bdbaddog in #4063 (comment)

@jcbrill - can you file an issue about additional arguments to vcvarsall.bat, I have some additional thoughts which would be good to capture in such an issue rather than here.

For discussion purposes, the author's proposed implementation for Items 1 and 3 is:

class MSVCScriptArgsError(VisualCException):
    pass

...

def msvc_setup_env(env):
    ...
    use_script = env.get('MSVC_USE_SCRIPT', True)
    if SCons.Util.is_String(use_script):
        use_script_orig = 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_orig))
        use_script_args = env.get('MSVC_USE_SCRIPT_ARGS', None)
        if use_script_args is not None:
            use_script_args_orig = use_script_args
            use_script_args_list = SCons.Util.flatten(use_script_args)
            try:
                use_script_args = ' '.join(use_script_args_list)
            except TypeError as e:
                error_msg = 'Script arguments specified by MSVC_USE_SCRIPT_ARGS must be a string or a sequence of strings:\nvalue: {}\n{}'.format(use_script_args_orig, str(e))
                raise MSVCScriptArgsError(error_msg)
            use_script_args = use_script_args.strip()
            if not use_script_args:
                use_script_args = None
        debug('MSVC_USE_SCRIPT String %s %s', repr(use_script), repr(use_script_args))
        d = script_env(use_script, use_script_args)
    elif SCons.Util.is_Dict(use_script):
        d = use_script
        debug('MSVC_USE_SCRIPT Dict %s', d)
    elif use_script:
        d = msvc_find_valid_batch_script(env,version)
        debug('MSVC_USE_SCRIPT True %s', d)
        if not d:
            return d
    else:
        debug('MSVC_USE_SCRIPT False')
        warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
                   "set correctly."
        SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
        return None
    ...

Comments:

  • There is a minor change to the existing implementation of the MSVCScriptNotFound error message: the original user-specified string is saved and then used in the error message rather than using the "stripped" version. This probably should have been in the author's original submission/implementation.
  • The debug messages have been slightly changed to more-readily identify the code path in the debug output (e.g., "MSVC_USE_SCRIPT 1" has been changed to "MSVC_USE_SCRIPT String").
  • MSVC_USE_SCRIPT_ARGS can be a scalar string or a list of strings. The utility function flatten is used to construct a list and type error exceptions due to the string join are reported to the user with the original user-provided content. The user-provided argument is type checked immediately with a user-friendly error message. The author finds that in some instances, a list is more useful from an end-user standpoint (e.g., comments after each argument in a list formatted across several lines).
  • MSVC_USE_SCRIPT is "overloaded" to allow a dictionary. This dictionary is intended to contain similar content as the SCons msvc detection (e.g., INCLUDE, LIB, LIBPATH, PATH, etc.). This dictionary is processed in approximately the same manner as the normal SCons msvc detection. An empty dictionary is intentionally passed through to the validation check that cl.exe is found on the derived system path.
@bdbaddog
Copy link
Contributor

For item 3, it should not overload MSVC_USE_SCRIPT, but rather be a separate env var altogether.
As you're not actually using a script, but rather pre-populating all the information provided by running the script and parsing whatever useful it's setting in that shell. Maybe MSVC_DICT_SETTINGS or something similar?

So let's split that entirely from the discussion of providing the ability to pass arguments to the specified script.(Item 1)

For item 2- MSVC_SCRIPT_ARGS seems clear enough

As always thanks for your thorough and complete discussion above.
(I'm always pleasantly surprised at the completeness, even if sometimes I need to read it several times to grasp it all and/or consume some more coffee first.. ;)

@bdbaddog bdbaddog added the MSVC Microsoft Visual C++ Support label Feb 28, 2022
@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 1, 2022

For item 3, it should not overload MSVC_USE_SCRIPT, but rather be a separate env var altogether. As you're not actually using a script, but rather pre-populating all the information provided by running the script and parsing whatever useful it's setting in that shell. Maybe MSVC_DICT_SETTINGS or something similar?

Agreed.

MSVC_USE_DICT is used below and has been implemented for testing in scons. This name was chosen as it's intention is similarly "parallel" to the intention of MSVC_USE_SCRIPT. In addition, MSVC_USE_DICT and MSVC_USE_SCRIPT would be consecutive entries in the documentation.

So let's split that entirely from the discussion of providing the ability to pass arguments to the specified script.(Item 1)

Fair enough. Prior to a PR for script arguments, the code relevant to MSVC_USE_DICT can easily be stripped out as it is only about 9 lines of code.

@bdbaddog Would it be OK to open another feature request issue for discussion purposes?

For item 2- MSVC_SCRIPT_ARGS seems clear enough

Works for me.

I have updated the variable name in my standalone script imported from site_cons and called from SConstruct to populate the environment to demonstrate capability.

As always thanks for your thorough and complete discussion above. (I'm always pleasantly surprised at the completeness, even if sometimes I need to read it several times to grasp it all and/or consume some more coffee first.. ;)

That is very kind.

I am struggling with one line in the existing documentation for MSVC_USE_SCRIPT which is given below. It is likely that I am missing something obvious. Please point out any misleading/misguided/false assertions on my part below.

Definitions of the existing and proposed environment variables:

  • MSVC_USE_SCRIPT [Item 1] - Unchanged from current documentation:

    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.

    I don't understand the statement: $MSVC_USE_SCRIPT overrides $MSVC_VERSION and $TARGET_ARCH.

    When MSVC_USE_SCRIPT is defined:

    • Given a user defined batch script, the current implementation does not attempt to accurately determine the MSVC_VERSION or the TARGET_ARCH. I'm not sure either are overridden in the strictest sense.
    • When MSVC_VERSION and/or MSVS_VERSION are "Truthy" (evaluates to True in a boolean context), the MSVC_VERSION is preserved or MSVC_VERSION is set to MSVS_VERSION. There is no override.
    • When MSVC_VERSION and MSVS_VERSION are "Falsy" (evaluates to False in a boolean context) either through definition (e.g., None) or omission (variables not defined), MSVC_VERSION is set to the lastest installed msvc version. MSVC_VERSION would only be overridden if it were defined and evaluates to False (e.g., None).
    • As the msvc detection is bypassed in its entirety, TARGET_ARCH is never set. If the user did not specify the TARGET_ARCH variable, the value of TARGET_ARCH in the environment is None.

    I believe that when MSVC_USE_SCRIPT is specified, while not required, it should be recommended practice to specify an accurate MSVC_VERSION as dependent scons msvc tools may query the (major) MSVC_VERSION with behavior dependent upon the queried value.

    If there are no scons detectable msvc installations, using MSVC_USE_SCRIPT without a MSVC_VERSION definition will not invoke the user specified batch file as there is no default msvc version which causes an early exit from the setup function.

  • MSVC_USE_SCRIPT_ARGS [Item 1] - Possible documentation:

    A string argument or a sequence of string arguments that is passed as an argument to the batch script specified by MSVC_USE_SCRIPT.

    A MSVCScriptArgsError exception is raised when the argument, or any of the arguments in the case of a sequence, is not a string.

    If MSVC_USE_SCRIPT is not defined, MSVC_USE_SCRIPT_ARGS is ignored.

  • MSVC_SCRIPT_ARGS [Item 2] - Possible documentation:

    A string argument or a sequence of string arguments that is appended to the script arguments for the script and script arguments determined by the msvc detection logic.

    A MSVCScriptArgsError exception is raised when the argument, or any of the arguments in the case of a sequence, is not a string.

    Comments:

    • No proposed scons implementation yet.

    • This feature overlaps with the variable MSVC_UWP_APP.

      The MSVC_UWP_APP variable could possibly be deprecated in favor of the more general MSVC_SCRIPT_ARGS. However, unlike MSVC_UWP_APP, MSVC_SCRIPT_ARGS is unchecked (see next item).

    • The current implementation silently ignores the MSVC_UWP_APP argument when the major msvc version is less than Visual Studio 2015 (i.e., Visual Studio 2013 and earlier):

      # VS2015+
      if maj >= 14:
          if env.get('MSVC_UWP_APP') == '1':
              # Initialize environment variables with store/UWP paths
              arg = (arg + ' store').lstrip()
      

      It would be a really good idea to issue a warning in this case as the user's intention/input is silently ignored (especially if the build succeeds):

       if env.get('MSVC_UWP_APP') == '1':
          # VS2015+
          if maj >= 14:
              # Initialize environment variables with store/UWP paths
              arg = (arg + ' store').lstrip()
          else:
              warn_msg = 'MSVC_UWP_APP is ignored for msvc versions 12.0 (VS 2013) and earlier'
              SCons.Warnings.warn(MyNewWarningType, warn_msg)
      
  • MSVC_USE_DICT [Item 3] - Possible documentation:

    Use a dictionary to set up the Microsoft Visual C++ compiler.

    SCons will prepend all dictionary items to the current environment ENV dictionary.

    A MSVCUseDictError exception is raised when the value is not a dictionary.

The detection algorithm priority sequence is straightforward:

  1. user-defined MSVC_USE_SCRIPT is a string (checked script name)
  2. user-defined MSVC_USE_DICT is not None (checked dictionary)
  3. default detection (when MSVC_USE_SCRIPT is undefined or is not a string that is "Truthy")
  4. bypass detection (when MSVC_USE_SCRIPT is defined and is not a string that is "Falsy")

Revised and tested proposed implementation for Items 1 and 3:

class MSVCScriptArgsError(VisualCException):
    pass

class MSVCUseDictError(VisualCException):
    pass

...

def msvc_setup_env(env):
    ...
    use_script = env.get('MSVC_USE_SCRIPT', True)
    use_dict = env.get('MSVC_USE_DICT', None)
    if SCons.Util.is_String(use_script):
        use_script_orig = 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_orig))
        use_script_args = env.get('MSVC_USE_SCRIPT_ARGS', None)
        if use_script_args is not None:
            use_script_args_orig = use_script_args
            use_script_args_list = SCons.Util.flatten(use_script_args)
            try:
                use_script_args = ' '.join(use_script_args_list)
            except TypeError as e:
                error_msg = 'Script arguments specified by MSVC_USE_SCRIPT_ARGS must be a string or a sequence of strings:\nvalue: {}\n{}'.format(use_script_args_orig, str(e))
                raise MSVCScriptArgsError(error_msg)
            use_script_args = use_script_args.strip()
            if not use_script_args:
                use_script_args = None
        debug('MSVC_USE_SCRIPT String %s %s', repr(use_script), repr(use_script_args))
        d = script_env(use_script, use_script_args)
    elif use_dict is not None:
        if not SCons.Util.is_Dict(use_dict):
            raise MSVCUseDictError('MSVC_USE_DICT type error: expected a dictionary, found {}'.format(type(use_dict).__name__))
        d = use_dict
        debug('MSVC_USE_DICT %s', d)
    elif use_script:
        d = msvc_find_valid_batch_script(env,version)
        debug('MSVC_USE_SCRIPT True %s', d)
        if not d:
            return d
    else:
        debug('MSVC_USE_SCRIPT False')
        warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
                   "set correctly."
        SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
        return None
    ...


The motivating example in PR 4102, using the SDK SetEnv.cmd batch file, is useful for illustrating the current scons behavior that may be unbeknownst to the user. Time permitting, expository examples to follow...

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 7, 2022

Also does it make sense for any _SCRIPT_ARTS to be a subst()'able string?

I'm not sure.

MSVC_USE_SCRIPT_ARGS probably should accept a scalar string or a list of strings. A list of string arguments can be more palatable from a user perspective.

Also, it would likely be a good idea to verify the argument is in fact a string or that the flattened list contains all strings and otherwise raise a user argument exception immediately with a sensible error message. It is probably bad news to pass an incorrect type down through the script environment calls.

This is what I have been using in my implementation:

class MSVCScriptArgsError(VisualCException):
    pass
...

    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))
        use_script_args = env.get('MSVC_USE_SCRIPT_ARGS', None)
        if use_script_args is not None:
            use_script_args_orig = use_script_args
            use_script_args_list = SCons.Util.flatten(use_script_args)
            try:
                use_script_args = ' '.join(use_script_args_list)
            except TypeError as e:
                error_msg = 'Script arguments specified by MSVC_USE_SCRIPT_ARGS must be a string or a sequence of strings:\nvalue: {}\n{}'.format(use_script_args_orig, str(e))
                raise MSVCScriptArgsError(error_msg)
            use_script_args = use_script_args.strip()
            if not use_script_args:
                use_script_args = None
        debug('MSVC_USE_SCRIPT String %s %s', repr(use_script), repr(use_script_args))
        d = script_env(use_script, use_script_args)
...

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 7, 2022

Off-topic trivia:

# FYI: MSVC_VERSION is necessary if there are no detected msvc instances (otherwise never invoked).

# This "passes" on 32-bit windows and 64-bit windows
env32 = Environment(
    MSVC_USE_SCRIPT      = 'C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin\\SetEnv.cmd',
    MSVC_USE_SCRIPT_ARGS = '/Release /x86 /2003'
)

# This "passes" on 32-bit windows and FAILS on 64-bit windows (no cl.exe on path)
env64 = Environment(
    MSVC_USE_SCRIPT      = 'C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin\\SetEnv.cmd',
    MSVC_USE_SCRIPT_ARGS = '/Release /x64 /2003'
)

Any guesses?

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 7, 2022

Do you have a copy of the debug log for both and/or what happens if you just run that on the command line? (I don't have MSVC 6 anywhere at the moment)

I already know the answer. This nicely encapsulates the issues with debugging this sort of problem.

The crux of the problem is the aggressively minimal SCons environment in which the msvc batch files are executed: when run directly from the command-line there are no errors/warnings. To add insult to injury, even when the MSCommon debugging is enabled, the "raw" stdout is not logged.

SCons does not include some of the windows system environment variables used by the setenv.cmd batch file.

SetEnv.cmd fragment:

IF "%TARGET_CPU%" =="x64" (
 IF "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( 
   IF EXIST "%VCTools%\x64\cl.exe" (
   SET "VCTools=%VCTools%\x64"
   ) ELSE (
   SET VCTools=
   ECHO The x64 compilers are not currently installed.
   ECHO Please go to Add/Remove Programs to update your installation.
   ECHO .
   )
 ) ELSE IF "%PROCESSOR_ARCHITEW6432%"=="AMD64" ( 
     IF EXIST "%VCTools%\x64\cl.exe" (
     SET "VCTools=%VCTools%\x64"
     ) ELSE (
     SET VCTools=
     ECHO The x64 compilers are not currently installed.
     ECHO Please go to Add/Remove Programs to update your installation.
     ECHO .
     )
 ) ELSE ( 
     IF EXIST "%VCTools%\x86_x64\cl.exe" (
     SET "VCTools=%VCTools%\x86_x64;%VCTools%"
     ) ELSE (
     SET VCTools=
     ECHO The x64 compilers are not currently installed.
     ECHO Please go to Add/Remove Programs to update your installation.
     ECHO .
     )
   ) 

The PROCESSOR_ARCHITECTURE and PROCESSOR_ARCHITEW6432 environment variables are not defined. This causes the else clause to be executed. On 64-bit platforms, the x64 compiler is installed in the x64 folder. On 32-bit platforms, the 64-bit compiler is installed in the x86_x64 folder. Therefore, x86_x64 does not exist and the message is echoed to stdout.

The message "The x64 compilers are not currently installed" is in fact generated when executed from SCons.

If the output were captured it would look something like this (taken from my own tools):

        "STDOUT": [
            "",
            "",
            "The x64 compilers are not currently installed.",
            "Please go to Add/Remove Programs to update your installation.",
            ".",
            "Setting SDK environment relative to C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0. ",
            "Targeting Windows Server 2003 x64 RELEASE",
            "",
            "*** WARNING ***",
            "You are currently building on a Windows 9x based platform.  Most samples have ",
            "NMAKE create a destination directory for created objects and executables.  ",
            "There is a known issue with the OS where NMAKE fails to create this destination",
            "directory when the current directory is several directories deep.  To fix this ",
            "problem, you must create the destination directory by hand from the command ",
            "line before calling NMAKE. ",
            ""
            ""
        ],

The warning is innocuous and generated because the "OS" environment variable is not defined. The older files expect OS to be defined. This is why the msvc 6.0 paths are in quotes: the batch file thinks it is 95/98/ME since OS is not "Windows_NT"

In addition, the SDK setenv.cmd batch files expect delayed expansion to be enabled which is typically not the default in a windows shell.

The /x86 target environment is "incomplete" but works anyway. Here is the resulting environment for the x86 invocation:

{
    "ENV": {
        "PATH": [
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Bin",
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin",
            "\\Microsoft.NET\\Framework\\v2.0.50727",
            "!Path!",
            "C:\\Windows\\System32"
        ],
        "INCLUDE": [
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Include",
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Include\\Sys",
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Include",
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Include\\gl",
            "!Include!"
        ],
        "LIB": [
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\VC\\Lib",
            "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Lib",
            "!Lib!"
        ],
        "LIBPATH": [],
        "VSCMD_ARG_app_plat": "",
        "VCINSTALLDIR": "C:\\Software\\MSVS-2005-80-Pro\\VC\\",
        "VCToolsInstallDir": ""
    },
    "TARGET_ARCH": null,
    "MSVC_USE_SCRIPT": "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin\\SetEnv.cmd",
    "MSVC_USE_SCRIPT_ARGS": "/Release /x86 /2003",
    "MSVC_VERSION": "14.3"
}

Due to delayed expansion not being enabled, !PATH!, !Include!, and !Lib! are not expanded. Also, the Framework path is incomplete due to "windir" not being defined.

SDK 6.0 contains stand-alone msvc 8.0 compilers.

I have a mind-bending intermediate windows batch file that sets the environment as appropriate in a setlocal/local block, calls the SDK batch file, and "exports" the non-windows wow64/system variables back into what would be the msvc batch file environment.

If interested, I could attach.

@jcbrill
Copy link
Contributor Author

jcbrill commented Mar 26, 2022

Status update:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement MSVC Microsoft Visual C++ Support
Projects
None yet
3 participants