How to properly configure the target OS version when creating a library on Windows using the Visual C ++ compiler

I am creating a cross-platform library using the Visual C ++ 2013 compiler with C ++ 11 features on the Windows platform, in particular using CMake (NMake generator) for the build system. I am using Windows 7.

My library uses some functions / enum values ​​/ structure elements, available only in Windows 8/7.

I want to be able to create a library for versions of Windows XP, Windows Vista, Windows 7 and Windows 8 / 8.1 and x86, x64 and arm architectures, i.e. not one build that just targets Windows XP and works everywhere, but many different builds designed for specific OSes, since newer versions of the OS have more useful features that my library can provide.

My questions:

  • How do I tell the compiler to target a specific version of the OS (e.g. XP, Vista, 7, 8, 8.1, etc.)?

  • How do I tell the compiler about targeting a specific architecture (i.e. x86, x64, arm, etc.)?

  • What happens if I use the functions / enum values ​​/ members, available only in Windows 8/7, but create my library oriented to Windows XP? Can the compiler warn me that such things do not exist in Windows XP? Or does it really compile but fail to run on Windows XP?

  • How to do this, when I compile for Windows XP, my code skips everything that is missing in Windows XP (Windows 7/8 functions, etc.)?

  • Does it matter which version of the Windows SDK I use when setting up different OS versions? I seem to have installed the 8.1, 8.0 and 7.1 Windows SDKs. Is it great if I always use the latest SDK even when targeting Windows XP?

Here are some answers that I found that I'm not sure are correct or complete:

  • I just need to set _WIN32_WINNT and WINVER for the corresponding values ​​for the target system and that it is, I do not need to install anything in addition to this, my application will work on the specified system (that is, Windows XP) with that.

    • I need to use the appropriate parameter when setting compiler environment variables using "C: \ Program Files (x86) \ Microsoft Visual Studio 12.0 \ VC \ vcvarsall.bat", that is, "C: \ Program Files (x86) \ Microsoft Visual Studio 12.0 \ VC \ vcvarsall.bat amd64 "for 64 bits.
    • I also need to specify the appropriate /SUBSYSTEM value for the linker, i.e. /SUBSYSTEM:WINDOWS,5.02 or /SUBSYSTEM:WINDOWS,6.00 for x64. But what is the difference between 5.02 and 6.00 ? Why do two values ​​indicate the same thing (64-bit)? Same for 5.01 and 6.00 , why both of them indicate 32-bit? I would decide that a single value for 64/32 bits would be enough.

      • Those values ​​( 5.01 , 5.02 and 6.00 ) are similar to the platform values ​​from WINVER from (1). Do they also install the target OS besides architecture? But WINVER=502 from (1) is used for targeting on Windows Server 2003, which was released in both 64-bit and 32-bit versions according to wikipedia, but here 5.02 stands strictly for 64-bit ones, which does not have meaning ...
  • The compiler could not compile, because WINVER define from (1) would exclude functions and other things that were not in OS targeting (Windows header files that define #ifdef things).

  • I should #ifdef things based on WINVER in my own code, such as Windows headers, and provide alternatives to missing functionality when required.

  • I do not know.

Please note that I am not using the Visual Studio IDE, so telling me to set the X parameter in the IDE is a little pointless.

I come from Linux development, so Windows stuff is a little new to me.

+6
source share
2 answers

Your answers to your questions are mostly correct. Some clarifications and corrections:

The subsystem version is orthogonal to the target architecture. What the /subsystem documentation says is that the minimum version of the subsystem for x86 is 5.01, and the minimum version of the subsystem for x64 is 5.02. For console and Windows applications, the version of the subsystem is the same as the version number of the internal operating system. 5.01 - x86 Windows XP; 5.02 - x64 Windows XP. There are two different version numbers for Windows XP because x64 Windows XP was released later than x86 Windows XP. Newer operating systems have the same version number for all architectures (for example, Windows Vista - version 6.0 for x86 and x64).

Please note that by installing the subsystem version, you can limit the set of operating systems on which your program will run. For example, if you install the subsystem version in 6.2, your program will only work on Windows 8 and above. If you try to run the program, for example. Windows 7, it will not work. (The same is true for DLLs: if you have an OS-oriented DLL that is newer than the OS you are running on, the loader will not load the DLL, at least not to execute the code.)

See the Wikipedia Microsoft Windows Version List for a list of operating system versions. Windows XP is the oldest version of Windows supported by Visual Studio 2013.

The Windows 8 SDK only supports software development up to Windows Vista. If you want to install _WIN32_WINNT or WINVER to build for Windows XP, you will need to use the Windows 7 SDK (Visual Studio 2013 will install both SDKs).

If your program is significantly different for each target operating system, it would probably be much easier to create one binary file that will work in the oldest operating system that you want to support (Windows XP), either with a delayed load or with dynamic loading ( via LoadLibrary / GetProcAddress ) any functions that you want to use from newer operating systems when this functionality is available.

+6
source

Sorry, this will be quite a long time: - (

1. How can I tell the compiler about setting up a specific version of the OS (for example, XP, Vista, 7, 8, 8.1, etc.)?

You usually don’t tell the compiler to target a specific version of the OS. Instead, you customize the header files from the SDK using WINVER and _WIN32_WINNT . sdkddkver.h header file provides useful named constants

If you set WINVER and _WIn32_WINNT high enough, the header files will declare functions available only in later versions of the OS (assuming you use the SDK, new enough to declare these functions).

But now you have a program that calls functions that might not be available in older versions of the OS. If you're lucky there is some kind of compatibility to help you. If you're out of luck, trying to call an unknown function simply won't succeed. Or do something much worse than fail. But this opinion, for my part, I cannot find anything concrete to quote.

2. How can I tell the compiler to target a specific architecture (ie x86, x64, arm, etc.)?

No. A different compiler is used for each target platform. If you look in C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ , you will find the bin directory and seven subdirectories:

amd64
amd64_arm
amd64_x86
arm
x86_amd64
x86_arm

You use compilers from the appropriate directory to create code for this platform. On a Win32 version of Windows, remove '(x86)' from the path above.

3. What happens if I use functions / enumerated values ​​/ structure elements, available only in Windows 8/7 ...

I am not sure if this behavior is defined. If you set _WIn32_WINNT to _WIN32_WINNT_WIN8, you pretty much say, "I intend to run this on Windows 8 and above." But that my opinion is not certain. I may not have read the documentation carefully enough.

4. How can I do this when I compile for Windows XP, my code skips everything that is missing in Windows XP (Windows 7/8 functions, etc.)?

You need to explicitly specify the code, I do not believe that you need something to solve this problem. You can do this at compile time with #ifdef and _WIN32_WINNT, or you can do this at runtime by determining whether you can call the function and then call the function or not call the function as necessary.

In the (unlikely) worst of all possible worlds, such mutable changes will occur that (for example) the Windows 8 structural parameter format is incompatible with an earlier implementation of the function. In this case, you need to find out which version of the structure to use when calling the function - and the header will give you only one structure definition based on the value of _WIN32_WINNT.

5. Does it matter which version of the Windows SDK I use when targeting different OS versions?

Maybe. Older versions of the SDK may not contain function definitions for later versions of the OS. For example, when the Vista SDK was created, most of the features introduced in Windows 8 probably did not exist.

Is it normal if I always use the latest SDK even when setting up on Windows XP?

This is probably the safest thing. If you use the latest SDK and set _WIN32_WINNT to _WIN32_WINNT_WINXP, then probably the right thing will happen if you want to start XP.

I say “maybe” because XP is something special. It is not supported. The latest SDK may or may not be tested with _WIN32_WINNT set to XP.

1. I just need to set _WIN32_WINNT and WINVER defines ...

This will give you a code file that will execute correctly on the OS version specified by _WIN32_WINNT. This, most likely, will also work on later versions of the OS (Microsoft tries to pretty much not break existing programs when they invoke a newer version of the OS). It may or may not work correctly in OS versions earlier than the one identified by _Win32_WINNT - I would not risk it.

• I need to use the appropriate option when setting compiler environment variables

Since you are using NMAKE, I am not sure about the answer to this question. The vcvarsall.bat file sets various environment variables that (among other things) can control which set of compilers are used (by controlling where MSBUILD searches for binary files, such as compilers). But I do not know if NMAKE starts MSBUILD or pays attention to these environment variables or has its own set of variables or what.

• I also need to specify the appropriate / SUBSYSTEM value for the linker, that is, /SUBSYSTEM:WINDOWS,5.02 or / SUBSYSTEM: WINDOWS.6.00 for x64

Primary / minor SUBSYSTEM values ​​have nothing to do with the type of platform (ARM, x86, x64, etc.). They determine the minimum OS level at which the code file will work. Therefore, SUBSYSTEM 5.01 says that "this code file will work on XP," while SUBSYSTEM 5.02 says that "this code file will work on Windows Server 2003, but not XP." Ideally, you should map the main / minor subsystem to _WIN32_WINNT to avoid the risk of the file working with an older version of the OS that cannot support it.

At least that I remember - I do not have an XP environment that I can use to confirm that I remember this correctly.

+4
source

Source: https://habr.com/ru/post/989458/


All Articles