尝试使 frama-c 在 Windows 7 上工作,使用 Perl 或 MinGW 或

trying to make frama-c work on Windows 7, using Perl or MinGW or

我想使用frama-c 进行静态C 代码分析。我已经花了一些努力(希望)正确安装它。这些文件位于 C:\CodeAnalysis\frama-c。我想通过 Windows 控制台应用它,例如:

C:\CodeAnalysis\frama-c\bin\frama-c hello.c

hello.c 只是一个简单的 hello-world-program(顺便说一句,我不是 C 程序员,而且是编程新手)

#include <stdio.h>

main()
{
 printf("Hello World \n");
}

所以当运行上面的命令有下面的输出:

[kernel] preprocessing with "gcc -C -E -I. hello.c"
C:/Strawberry/c/x86_64-w64-mingw32/include/stdio.h:141:[kernel] user error: syntax error
[kernel] user error: skipping file "hello.c" that has errors.
[kernel] Frama-C aborted: invalid user input

是的,我安装了 Perl,但不知道为什么 Frama 使用它。在我看来,stdio.h 似乎有点问题。这可以吗?但是我可以成功编译我的程序。

C:\Strawberry\c\bin\gcc hello.c 生成一个运行良好的 exe 文件。

从文件中删除include语句时,输出如下:

[kernel] preprocessing with "gcc -C -E I. hello.c"
hello.c:5:[kernel] warning: Calling undeclared function printf. Old style K&R code?

所以 frama 本身确实有效,这是我期望的输出类型。

我还安装了 MinGW 并试图让 Frama 使用它进行编译。所以我删除了 Windows 路径中的 Strawberry 条目。之后调用 frama-c 会产生相同的输出。

当完全卸载 Strawberry Perl 时,frama 不起作用(声明 gcc 是一个未知命令),尽管 C:\MinGW\mingw64\bin 也被添加到我的 Windows 路径中,即使是第一个条目。

C:\MinGW\mingw64\bin\gcc hello.c 有效,gcc hello.c 无效。

安装 Perl 后 gcc hello.c 可以工作,即使我从 Windows 路径变量中删除 Strawberry 部分也是如此。什么鬼?

我怎样才能使事情正常工作?

这里有几个问题,我们必须隔离它们才能解决问题。

  1. Strawberry Perl 安装自己的 gcc(基于 MinGW)、binutils、C headers 等,默认在目录 C:\Strawberry\c\bin 上。它将此目录(以及其他目录)添加到 Windows Path 变量。 Frama-C 期望 gcc 在路径中,如果路径中有多个包含 gcc 二进制文件的目录,则由 Windows 决定选择哪个 gcc。这就是 Frama-C 似乎使用它的原因。

  2. 一个常见错误(不是 Windows-specific,但由于其图形应用程序的性质,在 Windows 中更常发生)是修改环境变量而忘记重新启动仍然有它们的旧副本的进程(例如命令提示符)。如果对其值有任何疑问,echo %path% 应确认当前命令提示符的路径中存在哪些目录。

  3. 如果 echo %path% 包含预期值,这就是可能发生的情况(不幸的是我无法重现您的配置以对其进行彻底测试):在安装 Frama-C 期间,它可能会使用 在安装期间 中存在的设置来选择包含 gcc 的目录(在您的情况下,C:\Strawberry\c\bin),然后在其脚本中对该目录进行硬编码。

    这可以解释为什么在卸载 Strawberry Perl 后,即使路径中有另一个 gcc,Frama-C 也没有考虑它。理想情况下,在路径中使用单个 gcc 重新安装 Frama-C 可以让它这次找到正确的版本。请注意,这只是一个假设,我在这里可能完全错了。

    无论如何,您遇到的主要问题不是 gcc 本身,而是 Strawberry Perl 中包含的 headers,如下一项所述。

  4. 关于错误信息:

    C:/Strawberry/c/x86_64-w64-mingw32/include/stdio.h:141:[kernel] user error: syntax error
    [kernel] user error: skipping file "hello.c" that has errors.
    

    它确实没有提供太多信息,可能会在未来的版本中发生变化,但它确实指向导致错误的源代码行(文件 stdio.h,第 141 行):

    int __cdecl __mingw_vsscanf (const char * __restrict__ _Str,
        const char * __restrict__ Format,va_list argp);
    

    特别是,__restrict__ 似乎是此处错误的来源(Frama-C Sodium 接受 restrict__restrict,但不接受 __restrict__ ; 这可能会在未来的版本中改变)。

    不幸的是,即使修复此问题(通过在文件中的 #include <stdio.h> 之前添加例如 #define __restrict__ restrict)也不能保证文件的其余部分将被解析,因为它似乎是 Windows-specific, C++-prone header 可能包含其他不在 C99 标准中的 C definitions/extensions,并且可能不被 Frama-C.

最好的解决方案是确保 Frama-C 使用它自己的 stdio.h header,而不是 Strawberry Perl 的。它通常安装在 share/frama-c/libc 中(也就是说,它可能在您安装的 C:\CodeAnalysis\frama-c\share\frama-c\libc 中),但根据您的配置,执行期间可能找不到 headers,并且 Strawberry Perl 的 header 被包括在内。

针对此特定案例的快速破解可能是替换:

#include <stdio.h>

与:

#include "C:\CodeAnalysis\frama-c\share\frama-c\libc\stdio.h"

但这远非理想,可能会导致其他错误。

如果您设法找出如何防止 Strawberry Perl 的 header 被包含,并确保 Frama-C 的 header 文件被包含,您应该能够运行 Frama-C.

注意 Cygwin/MinGW 路径问题

我在使用 MinGW 编译器和 Cygwin 构建时遇到了一些问题(这不一定是个好主意),所以这里有一些关于如何构建 Frama-C Sodium 的快速说明 MinGW-based OCaml 编译器使用 Cygwin shell(但 不是 Cygwin-based OCaml 编译器),如果它可能对某人有帮助:

  1. 当 运行 宁 ./configure 时,您需要使用 Windows-based 路径而不是 Cygwin-based 指定 --prefix ] 一个,如:

    ./configure --prefix="C:/CodeAnalysis/build"

    如果不这样做,当 运行ning Frama-C(在 make/make install 之后)它将找不到 libc/__fc_builtin_for_normalization.i 文件,因为它会尝试使用Cygwin-based 路径,不适用于 MinGW-based OCaml 编译器。

    请注意,在指定前缀路径时不能使用反斜杠(\),因为它们稍后将无法正确转换。

  2. 我必须使用以下命令来确保 makefile 正常工作:

    make FRAMAC_TOP_SRCDIR="$(cygpath -a -m $PWD)"

    同样,这是由于 Cygwin 路径未被 MinGW 编译器识别(特别是 plug-ins 使用的绝对路径)。

  3. 前面的步骤足以编译和 运行 Frama-C(加上 GUI,如果您安装了 lablgtk 和其他依赖项)。但是,仍然存在一些问题,例如绝对 Windows 文件名并不总是被正确处理。这通常可以通过直接在命令行中使用相对路径指定文件名来避免(例如 frama-c-gui -val hello.c),但在一般情况下,MinGW+Cygwin 不是一个非常稳健的组合,可能会出现其他问题。

总的来说,由于路径的原因,混合使用 Cygwin 和 MinGW 不是一个好主意问题,但在这种情况下仍然可以编译和运行 Frama-C。