Prerequisites
The Windows MSVC environment does not provide the POSIX-style getopt.h / getopt() commonly used on Unix-like systems. As a result, when building C/C++ code originally written for Linux with MSVC, you will typically encounter errors such as:
fatal error C1083: cannot open include file: 'getopt.h'
Even if you add the header file, linking will still fail unless implementations of getopt(), getopt_long(), optind, optarg, and related symbols are available.
MSYS2 UCRT64 includes a MinGW-w64-derived getopt.h. The MSYS2 package mingw-w64-ucrt-x86_64-headers is distributed as MinGW-w64 headers for Windows and belongs to the UCRT64 repository. The package license is listed as ZPL-2.1 AND LGPL-2.1-or-later. (MSYS2 Packages)
However, the getopt.h file itself contains a disclaimer stating that no copyright has been assigned and that it has been placed in the Public Domain. (GitHub)
This article explains how to incorporate this MinGW-w64-derived getopt.h and getopt.c into an MSVC project to use getopt() and getopt_long().
Conclusion
The safest way to use getopt with MSVC is the following structure:
your_project/
include/
getopt.h
src/
getopt.c
main.c
Then compile getopt.c as part of your project:
cl /Iinclude src\main.c src\getopt.c
What you should not do is add MSYS2's entire /ucrt64/include or /ucrt64/lib directories to an MSVC project. This mixes MinGW-w64 and MSVC CRTs, headers, and libraries, which can easily lead to build and link problems.
1. Prepare the Files
Copy the following two files derived from MinGW-w64 into your project:
getopt.h
getopt.c
If MSYS2 UCRT64 is installed, getopt.h is typically located at:
C:\msys64\ucrt64\include\getopt.h
However, instead of adding the entire C:\msys64\ucrt64\include directory to the include path of an MSVC project, it is safer to copy only the required getopt.h into your project.
getopt.c is the implementation file from the MinGW-w64 CRT. The MSYS2 package mingw-w64-ucrt-x86_64-crt is distributed as MinGW-w64 CRT for Windows, and its package license is listed as ZPL-2.1. (MSYS2 Packages)
However, the getopt.c file itself contains a permissive license originating from Todd C. Miller and BSD-style license text originating from NetBSD. These licenses permit redistribution in source and binary form, provided that copyright notices, conditions, and disclaimers are retained or reproduced. (GitHub)
2. Minimal Example
main.c
#include <stdio.h>
#include <getopt.h>
int main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "ab:c")) != -1) {
switch (opt) {
case 'a':
printf("option -a\n");
break;
case 'b':
printf("option -b with argument: %s\n", optarg);
break;
case 'c':
printf("option -c\n");
break;
default:
printf("usage: %s [-a] [-b value] [-c]\n", argv[0]);
return 1;
}
}
for (int i = optind; i < argc; ++i) {
printf("non-option argument: %s\n", argv[i]);
}
return 0;
}
Build
From Developer Command Prompt for Visual Studio:
cl /Iinclude src\main.c src\getopt.c
Example execution:
main.exe -a -b hello file1 file2
option -a
option -b with argument: hello
non-option argument: file1
non-option argument: file2
3. Example Using getopt_long()
MinGW-w64's getopt.h also includes declarations for struct option, no_argument, required_argument, optional_argument, getopt_long(), and getopt_long_only(). (GitHub)
main.c
#include <stdio.h>
#include "getopt.h"
int main(int argc, char *argv[])
{
static struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "output", required_argument, 0, 'o' },
{ "verbose", no_argument, 0, 'v' },
{ 0, 0, 0, 0 }
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, "ho:v", long_options, &option_index)) != -1) {
switch (opt) {
case 'h':
printf("help\n");
break;
case 'o':
printf("output: %s\n", optarg);
break;
case 'v':
printf("verbose\n");
break;
default:
printf("usage: %s [--help] [--output file] [--verbose]\n", argv[0]);
return 1;
}
}
return 0;
}
Example Execution
main.exe --verbose --output result.txt
verbose
output: result.txt
4. Using It in a Visual Studio Project
For a .vcxproj project, configure it as follows.
File Layout
project/
include/
getopt.h
src/
getopt.c
main.c
Settings
| Item | Setting |
|---|---|
| C/C++ β General β Additional Include Directories | $(ProjectDir)include |
| Source Files | Add getopt.c
|
| Linker | No special additional libraries required |
If getopt.c is not added to the project, compilation may succeed but linking will fail. getopt.h only provides declarations; the actual definitions of getopt(), optind, and related symbols are contained in getopt.c. MinGW-w64's getopt.c provides definitions for optind, opterr, optopt, optarg, as well as implementations of getopt(), getopt_long(), and getopt_long_only(). (GitHub)
5. Do Not Mix MSYS2 Include/Lib Directories Directly into MSVC
Avoid configurations like:
C:\msys64\ucrt64\include
C:\msys64\ucrt64\lib
Adding these directories wholesale to MSVC include paths or library paths can mix MinGW-w64 headers and import libraries with MSVC's Windows SDK, UCRT, and CRT.
Problematic areas include:
| Area | Issue |
|---|---|
| CRT headers | MSVC CRT and MinGW-w64 CRT have different assumptions |
| Windows headers | Windows SDK versions and MinGW-w64 versions may conflict |
.a libraries |
GCC-oriented import libraries differ from MSVC .lib files |
| ABI | C++ and runtime boundary incompatibilities can occur |
Therefore, if you only want to use getopt with MSVC, it is better to copy getopt.h and getopt.c locally and compile them with MSVC rather than linking against the MSYS2 environment itself.
6. Licensing Considerations
getopt.h
MinGW-w64's getopt.h contains a disclaimer stating that no copyright has been assigned and that it has been placed in the Public Domain. (GitHub)
As a result, merely including getopt.h does not normally impose GPL/LGPL-style source disclosure obligations on your program.
getopt.c
The file requiring attention is getopt.c.
It contains at least the following license texts:
| Origin | Nature |
|---|---|
| Todd C. Miller portions | Permissive license similar to ISC/BSD |
| NetBSD Foundation portions | BSD 2-clause style license |
Both are permissive licenses and generally allow inclusion in commercial or closed-source products. However, the license terms require that copyright notices, conditions, and disclaimers be retained in source redistributions and reproduced in documentation or accompanying materials for binary redistributions. (GitHub)
Practical Compliance
When distributing binaries, provide something like:
THIRD-PARTY-NOTICES.txt
LICENSES/
getopt.txt
For safety, place the license comment block from the beginning of getopt.c into getopt.txt verbatim.
7. What Happens to the License of Your Binary?
Even if getopt.h and getopt.c are statically compiled into your application using MSVC, your entire application does not become GPL or LGPL.
The practical situation is:
| Item | Treatment |
|---|---|
| Your own source code | Any license you choose |
getopt.h |
Contains Public Domain disclaimer |
getopt.c |
Subject to permissive license conditions |
| Binary distribution | Include copyright notices, conditions, and disclaimers |
| Source disclosure obligation | Normally none |
| Commercial use | Normally allowed |
The important point is that the requirement is generally a notice obligation, not a source disclosure obligation.
8. Recommended Distribution Layout
Whether commercial or non-commercial, the following structure is recommended:
dist/
your_app.exe
README.txt
THIRD-PARTY-NOTICES.txt
Example THIRD-PARTY-NOTICES.txt:
This product includes getopt implementation derived from MinGW-w64 / OpenBSD / NetBSD sources.
The getopt.h file from MinGW-w64 states that it has no copyright assigned
and is placed in the Public Domain.
The getopt.c file contains permissive license notices from Todd C. Miller
and The NetBSD Foundation, Inc. The original copyright notices, permission
notice, conditions, and disclaimers are reproduced below.
[Paste the license comment block from the beginning of getopt.c here verbatim]
Even if your distribution is entirely in Japanese, it is safest to include the original English license text. If you add a translation, do not remove the original text.
9. Implementation Notes
Resetting optind
If getopt() needs to be run multiple times within the same process, optind must be reset:
optind = 1;
The MinGW-w64 implementation also supports BSD-style optreset, but for portability, using optind = 1 is generally preferable. getopt.h itself contains comments recommending that developers avoid relying on the non-standard BSD optreset for portability reasons. (GitHub)
Using from C++
getopt.h supports extern "C" and can therefore be used from C++ source files. (GitHub)
#include "getopt.h"
However, getopt.c should naturally be compiled as a C source file. In Visual Studio, leave its extension as .c when adding it to the project.
Separate Issue from /utf-8 and Unicode
getopt() operates on narrow strings from main(int argc, char *argv[]).
If you need precise handling of Unicode command lines on Windows, consider using wmain(int argc, wchar_t *argv[]) or CommandLineToArgvW() instead.
getopt should be viewed as a POSIX-style parser for narrow-character argv.
10. Summary
When using getopt with MSVC, the safest approach is:
- Copy
getopt.handgetopt.cinto your project. - Compile
getopt.cas part of the project with MSVC. - Do not add MSYS2's
/ucrt64/includeor/ucrt64/libdirectories wholesale to MSVC. - Treat
getopt.has having a Public Domain disclaimer. - Treat
getopt.cas permissively licensed and include copyright notices, conditions, and disclaimers in distributed materials. - Your own binary normally incurs no source disclosure obligation, but you should provide appropriate third-party notices.
In practical terms, the key points for MSVC are: build getopt.c together with your project, not just the header, and preserve the license notices from getopt.c in distributed materials.
Top comments (0)