我可以在 Bash 中调用 .cpp 程序吗?

Pri*_*hal 5 command-line bash scripts compiling c++

我是 Bash 编程的新手。我想在 Bash 文件中调用我的 C++ 程序。

我的程序是myProg.cpp

#include<iostream>
using namespace std;
int main()
{
   cout<<"Salam! World"<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的 bash 文件是myBash.sh. 如何在myBash.sh文件中调用我上面的 .cpp 程序?

kos*_*kos 10

您需要先编译它:首先将Terminal的当前工作目录更改为您的源文件路径:

cd <path_to_cpp_file>/
Run Code Online (Sandbox Code Playgroud)

然后编译源文件:

g++ myProg.cpp -o myProg
Run Code Online (Sandbox Code Playgroud)

然后你可以bash像这样从你的脚本中调用编译后的可执行文件:

cd <path_to_cpp_file>/
Run Code Online (Sandbox Code Playgroud)


Eli*_*gan 5

由于您的真正目标似乎是自动化运行程序所需的任何操作,因此我建议采用不同的方法。您可以使用makefile代替编写 shell 脚本。如果您愿意,您可以在您的 makefile 中编写一个规则,以便在构建后运行您的可执行文件。然后您将拥有两个文件——您的 C++ 源代码文件和您的 makefile——并且您将能够有效地运行单个命令:

  1. 构建或重建您的 C++ 程序,当且仅在必要时
  2. 运行你的程序。

这篇文章的后续部分解释了为什么不能.cpp直接调用文件(但必须先从它创建一个可执行文件);如何安装make,如何使用它,以及它在幕后做什么;以及如何避免常见的陷阱。但如果你想要得到的是什么这种方法看起来像在深入研究之前,你会遇到一个感觉,make run把这个后0Makefile

all: myProg

run: all
    ./myProg
Run Code Online (Sandbox Code Playgroud)

为此目的,我比 shell 脚本更喜欢它,我想你也可能如此。

背景

与Python 和 Bash 等一些解释型语言不同,C++ 是一种编译型语言1用 C++ 编写的程序必须在运行之前构建。(构建有时也称为编译,尽管更恰当的编译是指构建步骤之一。)您不能运行 C++源代码文件;它必须改为编译为目标代码2,在本例中为机器语言。然后必须将目标文件链接在一起,即使只有一个,它也必须链接到它使用的任何共享库。链接产生一个可执行文件 可以运行。

简而言之,您必须在第一次运行之前构建您的程序。在后续运行之前不需要重新构建它,除非您更改了它的源代码,在这种情况下,如果您希望您的更改反映在运行的程序中,则必须重新构建它。make实用程序专为这种情况而设计,在这种情况下,人们希望根据是否已经完成以及何时执行有条件地执行操作。

得到 make

您可能已经安装了该make命令;尝试运行它以找出答案。如果已安装,您将看到如下内容:

$ make
make: *** No targets specified and no makefile found.  Stop.
Run Code Online (Sandbox Code Playgroud)

要获得 make 你可以安装make 安装 make包,但我建议安装build-essential 安装 build-essential它提供了许多其他方便的工具。(您可能已经安装了build-essential 安装 build-essential获取g++,这是您可能已经拥有的一种方式make。)您可以使用软件中心来安装它或运行以下命令:

sudo apt-get update && sudo apt-get install build-essential
Run Code Online (Sandbox Code Playgroud)

make 没有 Makefile

要查看make工作原理,我建议先在没有 makefile 的情况下运行它,将源代码文件的基本名称传递给它:

$ make myProg
g++     myProg.cpp   -o myProg
$ ./myProg
Salam! World
Run Code Online (Sandbox Code Playgroud)

在后续运行中,make比较输入和输出文件上的修改时间戳 ( mtime s),并且不会不必要地重建您的程序:

$ make myProg
make: 'myProg' is up to date.
Run Code Online (Sandbox Code Playgroud)

当您更改时myProg.cpp,它会更新其修改时间戳,因此make将知道要重建它。(touch如果您需要或想要强制重建依赖于它的任何输出文件,您也可以使用该命令更新文件的时间戳。当然,删除输出文件也将确保在您运行时重建它们make--just don '不要删除错误的文件!)

$ touch myProg.cpp
$ make myProg
g++     myProg.cpp   -o myProg
Run Code Online (Sandbox Code Playgroud)

make跑步时怎么知道该怎么做make myProg

  • myProg参数make称为目标
  • 目标通常(但不总是)是要创建的文件的名称。目标可以在 makefile 中明确定义。
  • 当在 makefile 中未定义目标或(如在这种情况下)没有 makefile 时,make查找输入(即源代码)文件,以表明它们旨在构建目标的方式命名。
  • make从后缀(在本例中为.cpp)推断构建文件时要使用的实用程序和语法。

所有这些都可以定制,但在像这样的简单情况下通常不需要。

创建 Makefile 以自动构建和运行您的程序

要自动执行比从单个源代码文件构建程序更复杂的任务,例如如果有多个输入文件或(更适用于您的直接需要)除了运行编译器之外您希望完成的操作,您可以创建一个 makefile 来定义目标对于make并指定他们是如何依赖于其他的目标。

makefile 中定义的第一个目标是默认目标:它是make在没有命令行参数的情况下运行时尝试构建的目标(即,当您只运行make,而不是类似 的时候make myProg)。

使用 makefile 的通常方法是创建一个目录,其中包含用于构建程序的所有源代码文件(和任何其他文件)以及 makefile,通常称为Makefile. 按那个名字,make会自动找到它。

要创建一个可以用来运行的 makefile myProg,它会在必要时首先自动构建它,放在myProg.cpp新的目录中,否则为空目录。在该目录中创建另一个名为Makefile.

您可以为此使用任何文本编辑器,但是规则的配方——在它下面列出的将运行以使其成为目标的命令——必须用制表符而不是空格缩进。3因此,如果您的文本编辑器当前配置为在您按下 时使用空格缩进Tab,您应该更改此设置。

例如,在 Gedit 或 Pluma 中,您将进入Edit > Preferences,单击Editor选项卡,并确保未选中Insert Spaces 而不是 tabs

屏幕截图显示了 Pluma 中的首选项对话框——其界面与 Gedit 中的基本相同——指示了靠近编辑器选项卡顶部的插入空格而不是选项卡复选框的位置

许多编辑器默认使用制表符而不是空格缩进,因此如果您之前没有更改此设置,它可能已经为生成文件正确设置。

进入编辑器并(如有必要)将其配置为使用制表符缩进后,将其放入:

all: myProg

run: all
    ./myProg
Run Code Online (Sandbox Code Playgroud)

如果您复制并粘贴它,这将是错误的,因为即使您的文本编辑器在您按下 时没有生成空格,空格也会被处理Tab。(这与 Ask Ubuntu 显示代码的方式有关。)但是您可以简单地删除前面的四个空格./myProg,然后按Tab在它们的位置上创建一个制表符。

某些文本编辑器默认将制表符显示为 8 个空格或其他数字。没关系。

Makefile 有什么作用,以及如何使用它

使用命令:

  • make, 构建程序,除非它已经构建并且可执行文件是源代码的最新版本。或者,
  • make run, 运行程序,必要时首先构建它(即,如果当前没有可执行文件)。

这个 makefile 定义了两个目标:allrun.

  • all目标有没有自己的配方,而是取决于myProg目标。这个目标没有明确定义,所以它隐含地告诉make尝试myProg从当前目录中可用的任何源代码文件构建。(有关详细信息,请参阅上面的make无 Makefile部分。)

    因为all是在 中明确定义的第一个目标Makefile,所以它会在make从所在目录运行时构建Makefile。因此我们已经设置好了,所以单独运行make就相当于运行make all

  • run目标运行程序。它的配方由执行此操作的命令组成./myProgrunall目标声明为依赖项。这使得当您运行时make runmyProg如果当前的myProg可执行文件不是最新的(或尚不存在),则会重建。

    我们也可以使run依赖myProg而不是 on all,但我们仍然需要显式all目标(或不同名称的等效目标)来防止run成为默认目标。当然,如果你希望你的程序即使在你自己运行时也能构建和运行make,你可以这样做。

    依赖于all目标的另一个好处是,在你的程序应该运行之前,必须采取更多的行动。然后,您可以将配方添加到规则中all

如果需要构建,则使用 makefile 运行程序如下所示:

$ cd myProg/
$ make run
g++     myProg.cpp   -o myProg
./myProg
Salam! World
Run Code Online (Sandbox Code Playgroud)

或者这个,如果它不需要构建:

$ make run
./myProg
Salam! World
Run Code Online (Sandbox Code Playgroud)

如果您只想确保程序已构建(因为上次修改源代码文件)而不运行该程序,只需make不带参数运行即可:

$ make      # Here, I run make and myProg isn't current.
g++     myProg.cpp   -o myProg
$ make      # Running "make" again after "make" or "make run" does nothing.
make: Nothing to be done for 'all'.
Run Code Online (Sandbox Code Playgroud)

make myProg也仍然可以工作。)

改进:自定义编译器标志

make是一个非常强大的工具,对于像这样的简单目的很方便,但也非常适合大型、复杂的项目。尝试详细说明您可以做的所有事情make将是一本书(特别是本书)。

但是我想到您可能希望看到编译器发出的警告,当某些事情不会阻止构建完成但仍然是潜在错误时。这些不会捕获您编写的程序中的所有错误,但它们可能会捕获许多错误。

使用 GCC 时(与g++命令一样),我建议至少传递-Wall给编译器。这实际上并没有启用所有警告,但您可以使用-Wextra. 您有时可能还想要-pedantic. (请参阅GCC 参考手册中的man gcc3.8请求或抑制警告的选项。)

g++使用这些标志手动调用,您需要运行:

g++ -Wall -Wextra -pedantic -o myProg myProg.cpp
Run Code Online (Sandbox Code Playgroud)

为了使make调用C ++编译器(g++)与-Wall-Wextra-pedantic标志,添加一个CXXFLAGS=与他们行的顶部Makefile

CXXFLAGS=-Wall -Wextra -pedantic

all: myProg

run: all
    ./myProg
Run Code Online (Sandbox Code Playgroud)

尽管myProg仍然存在,并且比新myProg.cpp,运行makemake run编辑后Makefile仍会再次编译程序,因为Makefile现在比更新myProg。这是一件好事,因为:

  • 在这种情况下,如果有任何警告(对于该特定程序不应该有),重建可执行文件会导致您看到警告。
  • 更一般地说,有时当您编辑 makefile 时,是因为您希望生成不同的文件,或者生成具有不同内容的文件。(例如,如果您-O3为大量优化添加了标志或-g使编译器生成调试符号,则生成的myProg可执行文件会有所不同。)

进一步阅读

笔记

0:我建议进一步阅读以了解如何进行这项工作。但是,如果您想自己先尝试一下:您必须使用制表符而不是空格缩进行。

1:严格来说,几乎任何编程语言都可以解释或编译,这取决于它的实现方式。对于某些语言,解释器和编译器都存在。然而,解释型 C++ 并不常见——尽管并非闻所未闻

2:将构建分为编译链接,调用一个C++源代码文件(.cc/.cpp/.cxx/.C)的翻译成目标代码编译,并不是全部。C 和 C++(以及一些其他语言)的程序首先被预处理。在您的程序中,C 预处理器在实际编译开始之前#include<iostream><iostream>头文件的内容替换。在最狭义上,编译将源代码转换为汇编语言而不是目标代码。许多编译器(如 GCC/ g++)可以在一个步骤中结合编译和汇编,除非被要求,否则不会生成汇编代码。

虽然预处理是一个单独的步骤,但 GCC 和其他编译器会自动运行预处理器。同样,它们可以自动运行链接器,这就是为什么预处理编译汇编链接的整个序列有时被称为“编译”而不是“构建”的原因。(还要注意,构建可能包含的步骤不止这些——例如,它可能涉及生成资源文件、运行脚本来配置如何构建事物等)

3:您只需要在 makefile 本身中使用制表符进行缩进。使用 makefile 不会对您自己编写 C++ 源代码文件的方式强加任何要求。在处理其他文件时,可以随意将缩进从制表符切换回空格。(如果你真的不喜欢在 makefile 中使用制表符缩进,你可以设置.RECIPEPREFIX 特殊变量。)