如何使用 premake 生成 Syntastic 配置文件?

How can I generate a Syntastic config file using premake?

Syntastic 是 Vim 编辑器的源代码 linter 插件。

它使用外部工具进行各种语法和启发式检查。对于 C 和 C++ 代码,这通常涉及 运行 代码编译器。

为了调用编译器,Syntastic 读取一个配置文件,其中包含用于调用编译器的命令行参数。

显然,项目中的“真实”编译由 premake 处理,但这意味着可能有两个真实来源——写入 Syntastic 配置文件的编译器标志, 以及由 premake 写入构建脚本的编译器标志。

我想通过让 premake 在 Syntastic 配置文件中生成编译器标志来解决这个问题。

这似乎是一个相当简单的任务,有多种可能的方法——生成一个伪造的编译器,发明一个预构建任务,等等。但我对 premake 的内部结构知之甚少 这些方法中 是正确的。

如何让 premake 生成我的 syntastic.config 文件?

我查看了 premake5 下的几个不同的 kinds 项目——最近有几个项目被添加到文档中。 None 他们让我到达那里。

问题是我想要做的是“始终创建文件”或“在 premake5.lua 文件更改时创建文件”。这让事情变得困难,但并非完全不可能。

但是,生成的文件不是任何项目的输入文件,因此显然将它从困难推到了“不可能的 ATM”的边缘。

我尝试执行 premake 调用的操作 Custom Build Commands,但这需要生成的文件是一段源代码,它可以用来构建。如果不是这种情况,显然依赖关系图会中断,生成的 makefile 不依赖于该文件。 :(

为了让它正常工作,我选择始终使用预构建命令重新生成文件:

prebuildcommands {
    "$(SILENT) "
    ..repo_dir.."etc/write-syntastic-config.sh $(ALL_CFLAGS)"
    .." > "
    ..repo_dir.."etc/syntastic.config"
}

这里的关键值是$(ALL_CFLAGS),Makefile生成器用来保存我想要的东西的变量。

Syntastic 的配置文件及其对配置文件的使用有点棘手。它不接受 -L-l 选项,或者可能 gcc 在调用它的任何模式下都不接受它们。无论如何,需要进行一些过滤,可以使用 args。

此外,syntastic 处理专门查找 -I 的行,然后以特殊方式处理这些行:包含路径被视为绝对路径或相对于配置文件。

最后,syntastic 似乎不知道 -isystemgcc 的另一个包含目录选项。所以必须以不同的方式处理。

如果有人关心,这是我正在使用的脚本:

etc/write-syntastic-config.sh

#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

PENDING=""
PENDING_DIR=false

printf '# Generated by %s\n' "$(basename "[=11=]")"

CFG_FILE_DIR="$(dirname "[=11=]")"

for ARG in "$@"
do
    #printf >&2 "arg=>%s<\n" "$ARG"

    case "$ARG" in
    -I| \
    -L)
        PENDING="$ARG" 
        PENDING_DIR=true
        ;;

    -isystem)
        # -isystem is like -I, except syntastic doesn't know it
        printf '%s\n' "$ARG"
        PENDING_DIR=true
        ;;

    -I*|    \
    -L*)    PENDING_DIR=true
        PENDING="${ARG:0:2}"
        ARG="${ARG/#-?/}"

        ;;& #<-- Resume matching cases (i.e, "goto next case")

    *)  if $PENDING_DIR
        then
            ARG="$(realpath -m              \
                --relative-to "$CFG_FILE_DIR"       \
                "$ARG")"
        fi

        case "$PENDING" in
        -L) : ignore it ;;
        "") printf '%s\n' "$ARG" ;;
        *)  printf '%s %s\n' "$PENDING" "$ARG" ;;
        esac

        PENDING=""
        PENDING_DIR=false
        ;;
    esac
done

exit 0