我可以在 Bash 中呼叫 .cpp 程式嗎?

我可以在 Bash 中呼叫 .cpp 程式嗎?

我是 Bash 程式設計新手。我想在 Bash 檔案中呼叫我的 C++ 程式。

我的程式是myProg.cpp

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

我的 bash 檔案是myBash.sh.如何在myBash.sh檔案中呼叫上面的 .cpp 程式?

答案1

您需要先編譯它:首先將終端的目前工作目錄變更為原始檔的路徑:

cd <path_to_cpp_file>/

然後編譯原始檔:

g++ myProg.cpp -o myProg

然後您可以從bash腳本中調用編譯後的可執行文件,如下所示:

#!/bin/bash

# ...
<path_to_compiled_executable>/myProg
# ...

答案2

自從你的真正的目標似乎是自動化運行程式所需的任何操作,我建議採用不同的方法。您可以使用產生檔案如果您願意,可以在 makefile 中編寫一條規則,以便在建置可執行檔後執行該規則。然後,您將擁有兩個檔案——您的 C++ 原始程式碼檔案和 makefile——並且您將能夠有效地執行單一命令:

  1. 建立或重建您的 C++ 程序,當且僅當有必要時
  2. 運行你的程式。

本文的後續部分解釋了為什麼不能.cpp直接呼叫檔案(但必須先從中建立可執行檔);如何安裝make、如何使用它以及它在幕後做什麼;以及如何避免常見的陷阱。但是,如果您想在深入研究之前了解這種方法的樣子,那麼您將make run在放置此方法後運行0Makefile

all: myProg

run: all
    ./myProg

與 shell 腳本相比,我更喜歡用它來實現此目的,我想您也可能會喜歡。

背景

不像有些解釋性語言與 Python 和 Bash 一樣,C++ 是編譯語言1用 C++ 寫的程式必須是建成在它們運行之前。 (建築物有時也稱為編譯, 儘管編譯更正確地指的是建置步驟之一。原始碼文件;它必須被編譯成目標程式碼2, 在這種情況下機器語言。然後,目標文件必須連結在一起,即使只有一個,它仍然必須連結到任何共享庫它用。連結產生一個執行檔可以運行。

簡而言之,您必須在運行程式之前建置它,第一次。在後續運行之前不需要關於構建,除非您更改了其原始程式碼,在這種情況下,如果您希望您的更改反映在運行的程式中,則必須再次構建它。make實用性是專門為這種情況而設計的,人們希望執行操作有條件的取決於它們是否已經完成以及何時完成。

得到make

您可能已經make安裝了該命令;嘗試運行它來找出答案。如果已安裝,您將看到類似以下內容:

$ make
make: *** No targets specified and no makefile found.  Stop.

要獲得 make,您可以安裝製作 安裝make包,但我建議安裝建構必需的 安裝建置必需的它提供了許多其他方便的工具。 (您可能已經安裝了建構必需的 安裝建置必需的獲取g++,這是您可能已經擁有的一種方式make

sudo apt-get update && sudo apt-get install build-essential

make沒有 Makefile

要了解如何make工作,我建議首先在沒有 makefile 的情況下運行它,並將其傳遞給原始程式碼檔案的基本名稱:

$ make myProg
g++     myProg.cpp   -o myProg
$ ./myProg
Salam! World

在後續運行中,make比較修改時間戳(時間s) 在輸入和輸出檔案上,並且不會不必要地重建您的程式:

$ make myProg
make: 'myProg' is up to date.

當您變更時myProg.cpp,會更新其修改時間戳,因此make會知道要重建它。 (您也可以使用以下命令更新檔案的時間戳touch命令,如果您需要或想要強制重建依賴於該命令的任何輸出檔案。當然,刪除輸出檔案也將確保它們在運行時被重建make——只是不要刪除錯誤的檔案!

$ touch myProg.cpp
$ make myProg
g++     myProg.cpp   -o myProg

跑步時怎麼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 中,您可以進入編輯 > 首選項, 點選編輯選項卡,並確保插入空格而不是製表符未選取:

顯示 Pluma 中「首選項」對話方塊的螢幕截圖(其介面與 Gedit 中的介面基本相同),指示「編輯器」標籤頂部附近的「插入空格而不是選項卡」複選框的位置

許多編輯器預設使用製表符縮排而不是空格,因此如果您之前沒有更改此設置,則它可能已經為 makefile 設定正確。

進入編輯器並將其配置為使用製表符縮排後(如有必要),請將其放入:

all: myProg

run: all
    ./myProg

如果你複製貼上這個,就會出錯因為即使您的文字編輯器在您按 時沒有產生空格,空格也會被處理Tab。 (這與 Ask Ubuntu 顯示程式碼的方式有關。)但是您可以簡單地刪除前面的四個空格./myProg,然後按Tab在其位置建立一個製表符。

某些文字編輯器預設將製表符顯示為 8 個空格或其他數字。沒關係。

該 Makefile 的作用以及如何使用它

使用命令:

  • make,建置程序,除非它已經建置並且可執行檔對於原始程式碼來說是最新的。或者,
  • make run,運行程序,如有必要,請先建造它(即,如果目前沒有可執行檔)。

該 makefile 定義了兩個目標:allrun

  • 目標all沒有自己的配方,而是取決於myProg目標。該目標沒有明確定義,因此它隱式地告訴make嘗試myProg從當前目錄中可用的任何原始程式碼檔案進行建置。 (參見make沒有 Makefile有關詳細信息,請參閱上面的部分。

    因為all是 中明確定義的第一個目標,所以當從所在目錄運行Makefile時,它將被建置。因此,我們已經進行了設置,因此運行本身相當於運行。makeMakefilemakemake all

  • 目標run運行該程式。它的配方由執行此操作的命令組成./myProg。將目標run聲明all為依賴項。這使得當您執行 時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

或者這樣,如果不需要建置:

$ make run
./myProg
Salam! World

如果您只是想確保程式已建置(因為原始程式碼檔案上次修改)不運行程式,只需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'.

make myProg仍然可以工作。)

改進:自訂編譯器標誌

make是一個非常強大的工具,對於這樣的簡單目的來說很方便,但也非常適合大型、複雜的專案。試圖詳細說明你可以做的所有事情make將是一整本書(具體來說,這個)。

但我突然想到,當某些事情不會阻止建置完成但仍然是潛在錯誤時,您可能希望看到來自編譯器的警告。這些不會捕獲您編寫的程式中的所有錯誤,但它們可能會捕獲許多錯誤。

當使用 GCC(與命令一樣g++)時,我建議至少傳遞-Wall給編譯器。這實際上並沒有啟用全部警告,但您可以使用 啟用其餘大部分內容-Wextra。有時您可能也想要-pedantic。 (看man gcc3.8請求或抑制警告的選項在裡面海灣合作委員會參考手冊.)

g++使用這些標誌手動調用,您需要運行:

g++ -Wall -Wextra -pedantic -o myProg myProg.cpp

若要使用、和標誌make呼叫 C++ 編譯器 ( g++) ,請將包含它們的行加到 的頂部。-Wall-Wextra-pedanticCXXFLAGS=Makefile

CXXFLAGS=-Wall -Wextra -pedantic

all: myProg

run: all
    ./myProg

即使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 和其他編譯器會自動執行預處理器。同樣,它們可以自動運行連結器,這就是為什麼整個序列預處理,彙編,集會, 和連鎖有時稱為“編譯”而不是“建置”。 (另請注意,建置可能包含的步驟不只這些步驟——例如,它可能涉及生成資源檔案、運行用於配置建置方式的腳本, ETC。

3:您只需在 makefile 本身中使用製表符縮排即可。使用 makefile 不會對您編寫 C++ 原始碼檔案本身的方式施加任何要求。當您處理其他檔案時,可以隨意將縮排從製表符切換回空格。 (如果你真的不喜歡在 makefile 中使用製表符縮進,您可以設定.RECIPEPREFIX 特殊變數.)

答案3

這是一個範例:來自 myBash.sh

#!/bin/sh
g++ myProg.cpp -o myProg
./myProg

相關內容