【问题标题】:How to call clang-format over a cpp project folder?如何通过 cpp 项目文件夹调用 clang-format?
【发布时间】:2015-05-07 22:44:04
【问题描述】:

有没有办法为整个 cpp 项目文件夹调用类似 clang-format --style=Webkit 的东西,而不是为每个文件单独运行它?

我正在使用 clang-format.pyvim 来执行此操作,但我认为有一种方法可以应用一次。

【问题讨论】:

    标签: c++ clang clang-format


    【解决方案1】:

    不幸的是,没有办法递归地应用 clang 格式。 *.cpp 只会匹配当前目录中的文件,不匹配子目录。即使**/* 也不起作用。

    幸运的是,有一个解决方案:使用find 命令获取所有文件名并将它们通过管道输入。例如,如果要递归格式化目录foo/bar/ 中的所有.h.cpp 文件,你可以做

    find foo/bar/ -iname *.h -o -iname *.cpp | xargs clang-format -i
    

    更多讨论请参见here

    【讨论】:

    • 好吧,**/*.cpp 似乎在(相当现代的)bash 中工作。您之前可能需要shopt -s globstar
    • 如果您使用 CMake,this post 将向您展示如何使用 CMake 的 GLOB_RECURSE 查找所有 .cpp 文件并将它们传递给 clang-format
    • findxargs 的组合应该使用find ... -print0xargs -0 ... 以确保正确处理所有类型的文件名。
    • 如果 pwd 中存在任何 .cpp 或 .h 文件,此命令将失败。 find foo/bar/ -iname '*.h' -o -iname '*.cpp' | xargs clang-format -i 将解决此问题。
    【解决方案2】:

    怎么样:

    clang-format -i -style=WebKit *.cpp *.h
    

    在项目文件夹中。 -i 选项使其就地(默认情况下格式化输出写入标准输出)。

    【讨论】:

    • 或者如果您正在使用配置文件并希望格式化多种文件类型:clang-format-3.6 -i -style=file *.cpp *.h *.hpp
    • 不幸的是,这不会递归到子目录中。
    • 是的,*.cpp 将被 shell 扩展。 clang 只需要一个文件列表。更高级的选项(如递归通配符)取决于你的 shell 的特性。请参阅 unix.stackexchange.com/questions/49913/recursive-glob 了解如何使用 ** 构造。
    • clang-tidy 怎么样?
    • @AaronFranke 使用*.cpp 生成文件列表应该可以。 clang-tidy 命令允许传递多个文件。 ` 用法:clang-tidy [options] [... ] ` 但实际上这可能不是最好的方法。 Clang-tidy 执行更深入的分析,因此它需要每个文件的编译器标志等。当我使用 clang-tidy 时,我通常有一个“编译数据库”——一个 JSON 文件,其中包含每个文件的命令和一些脚本超过它。那是几年前的事了,也许现在有更好的方法。
    【解决方案3】:

    如果.clang-format文件不存在,先创建一个:

    clang-format -style=WebKit -dump-config > .clang-format
    

    选择您喜欢的任何预定义样式,或编辑生成的.clang-format 文件。

    clang-format configurator 很有帮助。

    然后运行:

    find . -regex '.*\.\(cpp\|hpp\|cc\|cxx\)' -exec clang-format -style=file -i {} \;
    

    cpphppcccxx 之外的其他文件扩展名可以在正则表达式中使用,请确保用\| 分隔它们。

    【讨论】:

    • 对于-style=file 有没有办法指定自定义文件路径?我试过-style=~/.clang-format 还是不行。
    • 我不知道,除了更改当前目录。
    • 我想出的 ghetto 解决方案是创建一个函数,它首先运行 cp ~/.clang-format . 然后在你的答案中运行 find 命令。
    • 很有趣,但它在 macOS 上对我不起作用。但是这个版本(带有 -E 标志并且没有转义特殊符号):find -E . -regex '.*\.(cpp|hpp|cc|cxx)' -exec clang-format -style=file -i {} \;
    • 感谢安东·布鲁索夫提供的信息。 -E 在 Arch Linux 上不起作用,但 -regextype egrep 可以。 -regextype egrep 也适用于 macOS 吗?
    【解决方案4】:

    我最近发现了一个 bash 脚本,它可以满足您的需要:

    https://github.com/eklitzke/clang-format-all

    这是一个 bash 脚本,将在您的代码上运行 clang-format -i

    特点:

    • 在 Ubuntu/Debian 上找到 clang-format 的正确路径,它在 clang-format 文件名中编码 LLVM 版本
    • 递归修复文件
    • 检测 C/C++ 项目最常用的文件扩展名

    在 Windows 上,我在 Git Bash 和 WSL 中成功使用它。

    【讨论】:

      【解决方案5】:

      对于 Windows 用户:如果您有 Powershell 3.0 支持,您可以:

      Get-ChildItem -Path . -Directory -Recurse |
          foreach {
              cd $_.FullName
              &clang-format -i -style=WebKit *.cpp
          }
      

      注意 1:如果您希望脚本前后的当前目录相同,请使用 pushd .popd

      注意2:脚本在当前工作目录下运行

      注意 3:如果这对你来说真的很重要,这可能会写在一行中

      【讨论】:

        【解决方案6】:

        当您使用 Windows (CMD) 但不想使用 PowerShell 大炮射击这只苍蝇时,试试这个:

        for /r %t in (*.cpp *.h) do clang-format -i -style=WebKit "%t"
        

        如果在 cmd 脚本中,不要忘记复制两个 %s。

        【讨论】:

          【解决方案7】:

          以下脚本和流程:

          1. Linux 中工作
          2. 应该在 MacOS 上工作
          3. Git For Windows 终端内的Windows 中使用clang-format downloaded and installed

          我是这样做的:

          我创建了一个run_clang_format.sh 脚本并将其放在我的项目目录的根目录中,然后我可以从任何地方运行它。这是它的样子:

          run_clang_format.sh

          #!/bin/bash
          
          THIS_PATH="$(realpath "$0")"
          THIS_DIR="$(dirname "$THIS_PATH")"
          
          # Find all files in THIS_DIR which end in .ino, .cpp, etc., as specified
          # in the regular expression just below
          FILE_LIST="$(find "$THIS_DIR" | grep -E ".*(\.ino|\.cpp|\.c|\.h|\.hpp|\.hh)$")"
          
          echo -e "Files found to format = \n\"\"\"\n$FILE_LIST\n\"\"\""
          
          # Format each file.
          # - NB: do NOT put quotes around `$FILE_LIST` below or else the `clang-format` command will 
          #   mistakenly see the entire blob of newline-separated file names as a SINGLE file name instead 
          #   of as a new-line separated list of *many* file names!
          clang-format --verbose -i --style=file $FILE_LIST
          

          使用--style=file 意味着我还必须在同一级别有一个自定义的.clang-format clang-format 说明符文件,我这样做了。

          现在,让您新创建的 run_clang_format.sh 文件可执行:

          chmod +x run_clang_format.sh
          

          ...并运行它:

          ./run_clang_format.sh
          

          这是我的示例运行和输出:

          ~/GS/dev/eRCaGuy_PPM_Writer$ ./run_clang-format.sh 
          Files found to format = 
          """
          /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo/PPM_Writer_demo.ino
          /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo2/PPM_Writer_demo2.ino
          /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.h
          /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.cpp
          /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/timers/eRCaGuy_TimerCounterTimers.h
          """
          Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo/PPM_Writer_demo.ino
          Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/examples/PPM_Writer_demo2/PPM_Writer_demo2.ino
          Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.h
          Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/eRCaGuy_PPM_Writer.cpp
          Formatting /home/gabriel/GS/dev/eRCaGuy_PPM_Writer/src/timers/eRCaGuy_TimerCounterTimers.h
          

          您可以在我的eRCaGuy_PPM_Writer 存储库和eRCaGuy_CodeFormatter 存储库中找到我的run_clang_format.sh 文件。

          参考资料:

          1. 我的存储库:
            1. eRCaGuy_PPM_Writer回购
            2. run_clang_format.sh file
          2. 关于如何在我的"git & Linux cmds, help, tips & tricks - Gabriel.txt" 文档中使用clang-format 的笔记在我的eRCaGuy_dotfiles 存储库中(在文档中搜索“clang-format”)。
          3. 官方clang-format 文档、设置、说明等! https://clang.llvm.org/docs/ClangFormat.html
          4. 在此处下载适用于 Windows 的 clang-format 自动格式化程序/linter 可执行文件或其他安装程序/可执行文件:https://llvm.org/builds/
          5. Clang 格式样式选项:https://clang.llvm.org/docs/ClangFormatStyleOptions.html
          6. [我的回答]How can I get the source directory of a Bash script from within the script itself?

          相关:

          1. [我的回答]Indenting preprocessor directives with clang-format

          另见:

          1. [我的回答]Fixing a simple C code without the coments

          【讨论】:

            【解决方案8】:

            我正在使用以下命令递归地格式化当前文件夹下的所有objective-C文件:

            $ find . -name "*.m" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format -i
            

            我在.bash_profile 中定义了以下别名以使事情变得更简单:

            # Format objC files (*.h and *.m) under the current folder, recursively
            alias clang-format-all="find . -name \"*.m\" -o -name \"*.h\" | sed 's| |\\ |g' | xargs clang-format -i"
            

            【讨论】:

              【解决方案9】:

              这是一种递归搜索并将所有文件以管道格式作为文件列表在一个命令中传输的解决方案。它还排除了“build”目录(我使用 CMake),但您可以省略“grep”步骤来删除它。

              shopt -s globstar extglob failglob && ls **/*.@(h|hpp|hxx|c|cpp|cxx) | grep -v build | tr '\n' ' ' | xargs clang-format -i
              

              【讨论】:

                【解决方案10】:

                在现代 bash 中,您可以递归地爬取文件树

                for file_name in ./src/**/*.{cpp,h,hpp}; do
                    if [ -f "$file_name" ]; then
                        printf '%s\n' "$file_name"
                        clang-format -i $file_name
                    fi
                done
                

                这里假定源位于./src.clang-format 包含格式信息。

                【讨论】:

                • 我不认为 globstar 在 bash 中默认是开启的,所以你需要设置它。
                【解决方案11】:

                @sbarzowski 在上面的评论中提到,在 bash 中,您可以启用 globstar,这会导致 ** 递归扩展。

                如果您只需要这个命令,您可以执行以下操作来格式化所有 .h.cc.cpp 文件。

                (shopt -s globstar; clang-format -i **/*.{h,cc,cpp})
                

                或者您可以将 shopt -s globstar 添加到您的 .bashrc 并在 bash 中一直使用 **

                作为旁注,您可能希望第一次使用带有 clang-format 的 --dry-run 以确保它是您想要的。

                【讨论】:

                  猜你喜欢
                  • 2021-09-12
                  • 2018-11-11
                  • 1970-01-01
                  • 2019-09-06
                  • 1970-01-01
                  • 2020-04-11
                  • 1970-01-01
                  • 2019-07-12
                  • 2018-07-28
                  相关资源
                  最近更新 更多