getopt.h:在Windows中编译Linux C代码

48

我试图在Windows下编译一组九个*.c文件(及相应的九个*.h文件)。

原始代码使用标准的GNU-Linux/C库“getopt.h”在Linux中接收命令行参数。而该库无法用于在Windows中构建C代码。

我想忽略现有代码的功能,问以下问题:熟悉C库“getopt.h”的人是否可以在基于POSIX风格的命令行参数的情况下对我的代码进行构建和运行?还是我必须重写代码以适用于Windows,并以不同的方式传递输入文件(放弃"getopt.h"依赖)?


2
如果MSVC支持不是必需的话,总有MinGW可用:我对随Cygwin一起提供的MinGW交叉编译器包非常满意... - Christoph
2
getopt.h 描述了 getopt.c 中提供的 API。从某个地方获取它,编译并将结果链接到您的应用程序中,就完成了。 - alk
3
关于alk评论中的一个小细节,从技术上讲它是可以做到的,但合法性完全取决于 getopt 源代码(如果有)和项目本身的许可证兼容性。一些 getopt 实现声明为公共领域,因此可能不会有问题。 - user2895783
9个回答

55

getopt()函数实际上非常简单。我为它制作了github gist,下面是源代码(来源)

#include <string.h>
#include <stdio.h>

int     opterr = 1,             /* if error message should be printed */
  optind = 1,             /* index into parent argv vector */
  optopt,                 /* character checked for validity */
  optreset;               /* reset getopt */
char    *optarg;                /* argument associated with option */

#define BADCH   (int)'?'
#define BADARG  (int)':'
#define EMSG    ""

/*
* getopt --
*      Parse argc/argv argument vector.
*/
int
  getopt(int nargc, char * const nargv[], const char *ostr)
{
  static char *place = EMSG;              /* option letter processing */
  const char *oli;                        /* option letter list index */

  if (optreset || !*place) {              /* update scanning pointer */
    optreset = 0;
    if (optind >= nargc || *(place = nargv[optind]) != '-') {
      place = EMSG;
      return (-1);
    }
    if (place[1] && *++place == '-') {      /* found "--" */
      ++optind;
      place = EMSG;
      return (-1);
    }
  }                                       /* option letter okay? */
  if ((optopt = (int)*place++) == (int)':' ||
    !(oli = strchr(ostr, optopt))) {
      /*
      * if the user didn't specify '-' as an option,
      * assume it means -1.
      */
      if (optopt == (int)'-')
        return (-1);
      if (!*place)
        ++optind;
      if (opterr && *ostr != ':')
        (void)printf("illegal option -- %c\n", optopt);
      return (BADCH);
  }
  if (*++oli != ':') {                    /* don't need argument */
    optarg = NULL;
    if (!*place)
      ++optind;
  }
  else {                                  /* need an argument */
    if (*place)                     /* no white space */
      optarg = place;
    else if (nargc <= ++optind) {   /* no arg */
      place = EMSG;
      if (*ostr == ':')
        return (BADARG);
      if (opterr)
        (void)printf("option requires an argument -- %c\n", optopt);
      return (BADCH);
    }
    else                            /* white space */
      optarg = nargv[optind];
    place = EMSG;
    ++optind;
  }
  return (optopt);                        /* dump back option letter */
}

6
我已将此包含在我的项目中,但当我尝试使用optarg时,它会说在Windows中未声明。getopt的返回值始终是opt。我该如何使用optarg? - eleijonmarck
6
头文件缺少 extern char *optarg;extern int optind, opterr, optopt; - cbr

27

你是正确的。 getopt() 是 POSIX 而不是 Windows,你一般需要重新编写所有解析命令行参数的代码。

幸运的是,有一个名为 Xgetopt 的项目专门为 Windows/MFC 类提供支持。

http://www.codeproject.com/Articles/1940/XGetopt-A-Unix-compatible-getopt-for-MFC-and-Win32

如果你能在你的项目中使其工作,它应该能够节省你相当多的编码时间,并防止你不得不重新构建所有解析代码。

此外,它还附带了一个很好的 GUI 演示应用程序,你会觉得它非常有用。

祝你好运!


我现在会尝试一下。但是我无法从您展示的链接中确定:这个库的API是否与旧的getopt API相同? - john_science
你能列举出任何重写代码的理由,但仅进行解析练习吗? - alk
好的,我正在移植的代码(用于更大的系统)已经有几个月了。但是开发它的人既是科学家又是工程师,所以他们通常不使用最新的编译器甚至不使用最新版本的UNIX/LINUX。因此,如果他们以一种老式的方式进行操作,那也不会让我感到惊讶。 - john_science
几个月来,getopt 没有出现任何问题 :-) 它可能还年轻或者已经很成熟了... 你可以尝试从我的回答中的链接中拉取 getopt 的源代码并使用它们。 - alk
@Dogbert 那几乎是完美的解决方案。但我正在尝试使用你提供的库(它是C++)与我当前拥有的代码库(它是C)运行时遇到了一些非常烦人的问题。我还没有放弃这将是可能的,但混合两种语言风格似乎会给Visual Studio构建增加一些复杂性。 - john_science

8

看起来你的库可能非常有用。我只是想说。但我先看到了Dogbert关于Xgetopt的评论,那就解决了问题。不过还是谢谢! - john_science
谢谢。这可以复制和粘贴,快速移植程序以快速使用。 - namezero

5

我已经在Windows下编译了getopt代码。

我的目的是在Windows命令行应用程序中显式地使用其命令行解析功能。

我成功地使用了VC2010实现了这一点。

据我所知,在此过程中没有遇到任何重大问题。

getopt.c getoptl.c


3
一个建议的编辑在这个答案中添加了句子“请注意,这个特定的代码是由GPLv3而不是LGPL覆盖的。”我回滚了它,并在此处包含了评论。 - Michael Petrotta
包括 getopt.in.h 吗? - Victor Sergienko
@VictorSergienko:当然,编译getopt的源代码需要一些来自getopt.in.h的代码。无论如何,我的回答并不是要让人们误解,即在没有任何(小)修改的情况下编译链接文件是可能的。只是将它们“原样”提供给VC10是行不通的。 - alk
还有一个位于 https://github.com/berkeleydb/libdb/blob/master/src/clib/getopt.c 的 getopt.c,旨在编译适用于各种操作系统。它采用BSD 3-Clause许可证。 - jifb

2
如果你只想在Visual C++中使用getopt而不需要其他依赖项,我已经从最新的GNU libc 2.12移植了getopt.c,并添加了所有新功能。唯一的区别是你必须使用TCHAR而不是char,但这在Windows中非常常见。
只需下载源代码,进行编译,将libgetopt.lib和getopt.h getopt_int.h复制到你的项目中即可。
你也可以使用根目录中的CMakeList.txt进行编译。 从GitHub下载源代码

1
根据文档,头文件getopt.h是GNU C库的特定部分,适用于Linux(和Hurd)。 POSIX标准化了getopt函数本身,并声明应与unistd.h中的optind optarg等一起使用。 我无法在Visual Studio上尝试此操作,但值得检查是否存在unistd.h并声明此函数,因为Visual Studio确实提供了其他POSIX函数。如果没有,则肯定会获取getopt的实现,而不是重写参数解析以使其在没有它的情况下工作。 Getopt的编写旨在使程序员更容易,命令行参数的用户更一致。 请务必检查许可证。

1
你可以尝试寻找glib-2.0作为替代方案,它可能有些庞大,但可以访问glib中的其他优秀工具。坦白说,我没有尝试过在Windows上使用它(我主要使用Linux),所以效果因人而异。获取glib在Windows上的使用方法:HowTo。建议使用mingw作为构建环境,使用visual studio作为IDE。Glib for Win32:HowTo。希望能帮到你。

-1

从我对 getopt.h 的记忆中,它所做的就是提供一个方便的解析器来处理你的主函数中的 argv 参数:

int main(int argc, char * argv[])
{
}

Windows控制台程序仍然有一个主方法,因此您可以简单地循环遍历argv数组并自行解析参数。例如:

for ( int i = 1; i < argc; i++ )
{
  if (!strcmp(argv[i], "-f"))
    filename = argv[++i];
}

谢谢! 我不确定这对我来说是否实用。虽然我明白我可以滚动查看大约5000行的代码,并重写这些部分,但这是我们从其他开发人员那里获得的代码。 那么,在两个月后,当他们给我们稍微更新了一点的代码时,会发生什么?每次我们更新时都需要重新做参数处理代码吗?这听起来很耗时间。 - john_science
1
听起来你需要与其他开发人员一起商定一个可移植的参数传递系统。@theJollySin提供的解决方案可能是答案,但无论如何编写一个可移植的参数解析器都不难。 - Benj
2
随着时间的推移,getopt API 对我来说看起来非常稳定。@theJollySin - alk
为什么要手动操作,当互联网上有“getopt”函数可用呢? - bobobobo

-1

找到 getopt.h 并不是我的问题。我更担心 Windows 的 getopt.h 在 Linux 环境下是否能够正常工作。不过现在知道了,还是很好的。 - john_science
无法在 Windows 上编译。 - Varun Garg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接