Gcc

通過在實際的 C/C++ 源文件中包含預處理器建構指令來編譯 C/C++ 程式碼

  • January 13, 2019

我有理由不想依賴特定的建構系統。我並不是要否定任何人的最愛,但我真的只想堅持編譯器附帶的內容。在這種情況下,GCC。Automake 存在一定的兼容性問題,尤其是與 Windows 的兼容性問題。<3 GNU make 非常有限,以至於經常需要用 shell 腳本來補充。Shell 腳本可以有多種形式,長話短說可能會惹惱很多人,這就是我想做的——

主要的切入點是上帝。無論是 C 或 C++ 源文件,它都是應用程序的中心。我不僅希望主入口點是第一個被執行的東西,我還希望它是第一個被編譯的東西。讓我解釋 -

曾經有一段時間,專有和閉源庫很常見。多虧了蘋果轉向 Unix 和微軟自取其辱,那個時代已經結束了。任何需要動態連結的庫都可以作為應用程序的支持文件包含在內。出於這個原因,.SOs(可能還有 .DLLs ;])的單獨建構指令都很好而且很花哨,因為它們是單獨的執行檔。任何其他庫都應該是靜態連結的。現在,讓我們談談靜態連結——

靜態連結是一個真正的婊子。這就是 makefile 的用途。如果整個項目是用一種語言(例如 C 或 C++)編寫的,您可以 #include 庫作為標頭檔。那很好。但是現在,讓我們考慮另一種情況——

假設您和我一樣,無法弄清楚 C 為字元串提供的困難藉口,因此您決定使用 C++。但是您想使用 C 庫,例如 MiniBasic。上帝幫助我們。如果 C 庫的設計不符合 C++ 的語法,那你就完蛋了。這就是 makefile 出現的時候,因為您需要使用 C 編譯器編譯 C 源文件,並使用 C++ 編譯器編譯 C++ 源文件。我不想使用makefile。

我希望有一種方法可以利用 GCC 的預處理器宏來告訴它這樣的事情:

你好,海灣合作委員會。你好嗎?如果您忘記了,您現在正在查看的這個源文件是用 C++ 編寫的。你當然應該用 G++ 編譯它。該文件還需要另一個文件,但它是用 C 語言編寫的。它被稱為“lolcats.c”。我希望你用 GCC 將那個編譯成一個目標文件,我希望你用 G++ 將這個編譯成主目標文件,然後我希望你將它們連結到一個執行檔中。

我怎麼能用預處理器術語寫這樣的東西?海灣合作委員會甚至這樣做嗎?

主要的切入點是上帝。無論是 C 或 C++ 源文件,它都是應用程序的中心。

只是以同樣的方式,氮是松樹的中心。它是一切開始的地方,但沒有任何關於 C 或 C++ 讓您將應用程序的“中心”放在main().

許多 C 和 C++ 程序都建立在事件循環I/O 泵上。這些是此類計劃的“中心”。您甚至不必將這些循環main().

我不僅希望主入口點是第一個被執行的東西,我還希望它是第一個被編譯的東西。

在 C 或 C++ 源文件中放在main() 最後實際上是最容易的。

C 和 C++ 不像某些語言,符號可以在聲明之前使用。放在首位main()意味著您必須提前聲明其他所有內容。

曾經有一段時間,專有和閉源庫很常見。多虧了蘋果轉向 Unix 和微軟自取其辱,那個時代已經結束了。

告訴我,我在做夢!

OS X 和 iOS充滿了專有程式碼,而且微軟不會很快消失。

無論如何,微軟目前的困難與你的問題有什麼關係?您說您可能想要製作 DLL,並且您提到 Automake 無法有效應對 Windows。這告訴我,微軟在你的世界中也依然重要。

靜態連結是一個真正的婊子。

真的嗎?我一直發現它比連結到動態庫*更容易。*這是一種更古老、更簡單的技術,出錯的事情更少。

靜態連結將外部依賴項合併到執行檔中,以便執行檔獨立、自包含。從您的其餘問題來看,這應該會吸引您。

你可以#include庫作為標題

不…您是#include 庫標題,而不是庫。

這不僅僅是迂腐。術語很重要。它是有意義的。

如果你可以#include圖書館,#include &lt;/usr/lib/libfoo.a&gt;會工作。

在許多程式語言中,這就是外部模組/庫引用的工作方式。也就是說,您直接引用外部程式碼。

C 和 C++ 不屬於以這種方式工作的語言。

如果 C 庫的設計不符合 C++ 的語法,那你就完蛋了。

不,你只需要學習使用 C++。具體在這裡,extern "C".

我怎麼能用預處理器術語寫這樣的東西?

#include它對另一個 C 或 C++ 文件是完全合法的:

#include &lt;some/library/main.cpp&gt;

#include &lt;some/other/library/main.c&gt;
#include &lt;some/other/library/secondary_module.c&gt;

#include &lt;iostream&gt;

int main()
{
  call_the_library();
  do_other_stuff();
  return 0;
}

我們在這裡不使用extern "C",因為這會將其他庫中的 C 和 C++ 程式碼直接提取到我們的 C++ 文件中,因此 C 模組也需要是合法的 C++。C 和 C++ 之間有許多令人討厭的小差異,但是如果您要混合使用這兩種語言,那麼無論如何您都必須知道如何處理它們。

這樣做的另一個棘手部分是,#includes如果是連結器命令,則 的順序比庫引用的順序更敏感。當你以這種方式繞過連結器時,你最終不得不手動做一些連結器會自動為你做的事情。

為了證明這一點,我使用 MiniBasic(您自己的範例)並將其script.c驅動程序轉換為獨立的 C++ 程序,#include &lt;basic.c&gt;而不是#include &lt;basic.h&gt;. ( patch ) 為了證明它現在真的是一個 C++ 程序,我將所有printf()呼叫都更改為cout流插入。

我不得不做一些其他的改變,所有這些都在一個將 C 和 C++ 混合的人的日常工作中做得很好:

  1. MiniBasic 程式碼利用了 C 允許自動轉換void*到任何其他指針類型的意願。C++ 讓你變得明確。
  2. 較新的編譯器不再允許在上下文中使用 C 字元串常量(例如"Hello, world!\n") 。char*該標准說編譯器允許將它們放入只讀記憶體中,因此您需要使用const char*.

就是這樣。只需幾分鐘的工作,修補 GCC 投訴。

basic.c我必須對連結的script.c更新檔文件中的內容進行一些類似的更改。我沒有費心發布差異,因為它們幾乎相同。

要解決此問題,請研究SQLite Amalgamation,與SQLite source tree相比。SQLite 不會將#include所有其他文件都使用到單個主文件中;它們實際上是串聯在一起的,但這#include在 C 或 C++ 中也是如此。

引用自:https://unix.stackexchange.com/questions/145527