如何编译目录中的所有cpp文件?

19

我有一些源文件在多个文件夹中.. 有没有一种方法可以在不用一个一个命名它们的情况下将它们全部编译?

我知道我可以这样说

g++ -o out *.cpp 

但是当我尝试的时候

g++ -o out *.cpp folder/*.cpp

我遇到了一个错误。

正确的做法是什么?我知道可以通过Makefile来实现,但是能否直接使用g++完成呢?

4个回答

21

通过指定 folder/*.cpp,您告诉 g++ 编译 folder 中的 cpp 文件。这是正确的。

您可能忽略了告诉 g++ 额外文件所在的位置,这些文件被 cpp 文件 #include

为此,请告诉编译器也使用 -I 包含该目录,如下所示:

g++ -o out -I ./folder *.cpp folder/*.cpp

有时编译器会忘记根/当前目录中的内容,因此我用另一个-I手动指定了当前目录.

g++ -o out -I . -I ./folder *.cpp folder/*.cpp

1
如果文件夹有子文件夹怎么办?它会自动包含子文件夹进行编译吗? - TomSawyer
@TomSawyer 不,这种方法需要您手动指定单个目录。对于递归情况,使用shell脚本或Makefile构建这些条目是合适的。相关主题:https://dev59.com/B2Ij5IYBdhLWcg3w8ZUF,https://dev59.com/rXRB5IYBdhLWcg3wyqKo - Bit Fracture
VS Code的文档(https://code.visualstudio.com/docs/cpp/config-msvc)中提到: 您可以通过使用类似"${workspaceFolder}\*.cpp"的参数来修改tasks.json以构建多个C++文件,而不是使用${file}。 但是,该网站使用CL编译器,当我尝试使用g++时似乎无法正常工作。 - Jonas De Schouwer
我之前使用mingw-64,但是它没有起作用。 - BlueStaggo

11

想通了! :) 我不喜欢使用 make 或者构建系统来编译我的代码,但是我想将我的代码分成子文件夹以保持整洁和有组织性。

运行以下命令(将 RootFolderName(例如 . )和 OutputName 替换为实际值):

g++ -g $(find RootFolderName -type f -iregex ".*\.cpp") -o OutputName

使用find命令进行递归不区分大小写的正则表达式搜索(-iregex)文件(-type f)。将其放入$()中,然后将结果注入到您的g++调用中。太棒了!:)

当然,确保您正在正确使用该命令;您始终可以进行测试运行。


对于那些使用Visual Studio Code编译的人,我必须在带有"command": "g++"任务的tasks.json args: []中执行此操作:

"-g",
"$(find",
"code",
"-type",
"f",
"-iregex",
"'.*\\.cpp')",
"-o",
"program"
< p >(否则它会将< code >$()全部用单引号包裹起来。)


(感谢:user405725 @ https://stackoverflow.com/a/9764119/1599699的评论)


有趣(指奇怪的)——我讨厌没有构建系统控制编译的想法,手动运行编译器而不是拥有永久(和版本控制的)记录所需文件、编译选项等,让我感到不安。实际上,我从来不使用默认选项运行编译器——通常需要一些额外的选项,以获取额外的警告,或控制方言,或提供对外部资源(头文件、库)的访问等。 - Jonathan Leffler
1
@JonathanLeffler 这是一个一行代码完成所有编译的方法,这让我感到非常轻松。在我看来,拥有复杂的构建系统更糟糕。这个一行代码也是版本控制的。 - Andrew
不同时代,不同的观点。 - Jonathan Leffler
2
感谢您的提示。为了从vscode递归地编译当前文件夹中的所有cpp文件,我必须稍微修改tasks.json文件中的args字段为["-g", "$(find", "${fileDirname}", "-type", "f", "-iregex", "'.*\\.cpp')", "-o", "${fileDirname}/${fileBasenameNoExtension}"]。关键点在于变量fileDirname表示当前文件的父文件夹,以及fileBasenameNoExtension表示当前文件的名称(不带扩展名)(在Windows上可能需要添加.exe)。 - Alka
@Alka 是的,那可能更好,并且跨平台吧。如果它可以跨平台,您可以随意进行编辑。嗯...另一个答案已经有这个了? - Andrew

0

我遇到了这个问题,看到了上面的vscode任务,并找到了另一种解决方案。这将从同一目录获取所有头文件和c文件。然后可以使用F5键。

tasks.json

{
  "tasks": [
    {
      "type": "shell",
      "label": "C/C++: gcc-7 build active file",
      "command": "/usr/bin/gcc-7",
      "args": [
        "-I",
        "${fileDirname}",
        "-g",
        "${fileDirname}/*.c",
        "-o",
        "${fileDirname}/${fileBasenameNoExtension}"
      ],
      "options": {
        "cwd": "${workspaceFolder}"
      },
      "problemMatcher": [
        "$gcc"
      ],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ],
  "version": "2.0.0"
}

0

如果所有文件都包含自己的主函数,并且它们不是同一个项目/程序的一部分,您可能希望保留它们的原始名称并为每个文件创建一个可执行文件。如果是这种情况,您可以使用 awk

awk '{n=split(FILENAME, a, "."); outfile=sprintf("%s.out",a[n-1]); command=sprintf("g++ -I . %s -o %s", FILENAME, outfile); system(command); nextfile } ' *.cpp

首先,使用split将文件名和扩展名分开,并将结果存储到一个数组a中。基本名称位于索引n-1处,扩展名位于索引n处。因此,我们将扩展名更改为.out,并使用sprintf存储到outfile变量中。同样地,我们通过system函数在shell中创建要执行的命令。
以上命令的最短版本为:
awk '{n=split(FILENAME, a, "."); command=sprintf("g++ -I . %s -o %s.out", FILENAME, a[n-1]); system(command); nextfile } ' *.cpp

你也可以像@Bit Fracture建议的那样,使用-I来包含其他文件。

注意:如果任何文件名包含空格或多个点,则此解决方案效果不佳。在执行命令之前,这些字符需要替换为下划线,例如,如此处所述:

find . -type f -name "* *.cpp" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

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