關於Windows下C/C++的編譯
文章目錄
一、前提
在編譯器中,我們編譯程序的過程主要分成以下四個階段。
- 預處理
- 編譯
- 彙編
- 鏈接
具體的實現過程是按照以下的方式來進行的。接下來我們以這個編譯器爲例,以及這個文件爲源文件完成對以上過程的理解。
(一)預處理
這一階段的過程主要是對包含源代碼的文本文件進行處理。主要的處理內容就是將在源文件中包含的頭文件加載到文件中,替換宏定義等等。最終生成的文件是以結尾的文本文件。
clang++ -E test.cpp -o test.i
(二)編譯
這個階段是將預處理得到的文件經由編譯器變成彙編語言。彙編語言中的每一條語句都以一種標準的文本格式準確的描述一條地址機器指令。在這個階段生成的文件纔是機器相關的代碼。這個階段生成以結尾的彙編文本文件。
clang++ -S test.i -o test.s
(三)彙編
這個階段就是將上一步得到的彙編文件彙編成機器指令,從而把這些指令打包成爲一種可重定向的目標程序格式。這個時候生成以結尾的二進制文件。
clang++ -c test.s -o test.o
(四)鏈接
這個階段主要是處理在文件中調用了系統庫例如等函數,那麼就需要將系統庫中的合併到我們生成的中。生成可執行的以結尾的二進制文件。
clang++ test.o -o test.exe
二、使用clang命令
瞭解了以上的編譯過程之後,就有人產生疑問了,那麼爲什麼我們在通常進行編譯的時候採用的命令只有以下的一行:
clang++ test.cpp -o test.exe
其實,早已經將我們以上的四個步驟全部整合爲以上的一條命令。這樣就使得我們在進行編譯的時候不必要生成過多的對運行沒有意義的文件。只有在有需求的時候我們纔去生成指定文件。
(一)包含外部的頭文件
這個問題其實是在我的一個項目中用到的。在那個項目中我需要使用到這個外部庫。可是網上一搜全部是以或者其他的爲載體來完成的。這對於我這種不喜歡繁重編譯器的人來說這簡直就是折磨。於是我自己在命令行配置了併成功運行。
那麼我們現在說一說關於怎樣包含外部庫。其實很簡單,假設我們在編寫的時候,需要用到一個的庫,但是這個庫並不在我們的標準庫文件中。我們需要做的僅僅是在編譯的時候在後加上一個參數就好。如下:
clang++ --help
>> -I <dir> Add directory to include search path
// opencv.cpp
#include <opencv/opencv.hpp>
...
假設我們的以上包含的目錄在裏,那麼我們的編譯命令變成了:
clang++ opencv.cpp -o opencv.exe -I D:/opencv/build/include
(二)包含外部的靜態庫
在中,靜態庫是以結尾的文件。有時候我們編譯生成的文件也是需要使用到的。那麼怎麼將外部的文件連接到我們的目標文件中呢?
我們仍然是藉助的功能:
clang++ --help
>> -L <dir> Add directory to library search path
那麼我們完全可以使用以下的命令對原來的數據進行編譯:
假設我們的文件在以下的文件夾當中。
clang++ opencv.cpp -o test.exe -I D:/opencv/build/include -L D:/opencv/build/x64/vs15/lib
(三)連接靜態庫
到現在爲止,我們靜態庫已經包含完成,但是怎麼鏈接呢,這是個問題,因爲不進行鏈接的話就無法完成外部庫中函數的調用。會產生類似於以下的報錯:
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_init,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_options,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_real_connect,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_error,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_query,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_use_result,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_fetch_row,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_num_fields,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_free_result,該符號在函數 main 中被引用
connect-bd0e58.o : error LNK2019: 無法解析的外部符號 mysql_close,該符號在函數 main 中被引用
也就是說會產生無法解析的外部符號的錯,這就表明我們只是將數據包含進來,但是並沒有鏈接成功。我們需要對其進行鏈接操作。對於靜態庫的鏈接有以下兩種方式:
1.代碼中鏈接
代碼中鏈接是採用預處理的方式:
#pragma comment(lib, "libmysql")
這樣就能實現鏈接到靜態庫的作用。
2.編譯時命令行鏈接
編譯時鏈接靜態庫方法就是,就加靜態庫名字。
clang++ opencv.cpp -o test.exe -I D:/opencv/build/include -L D:/opencv/build/x64/vs15/lib -llibmysql
這樣就完成了對靜態庫的鏈接。
(四)包含動態庫
在下,動態庫一般是以結尾的文件。那麼怎樣包含呢?實際上如果不包含動態庫,在之前的各個階段都不會有問題。因爲動態庫是運行時才用得到的庫。因此在界面中,往往會提示你缺少動態庫請重新安裝後使用。但是在命令行下就十分的狡猾,他甚至不提示任何東西,代碼一行也不執行!甚至連最簡單的寫在函數的第一行的輸出都不執行。而且表面上看起來沒有任何異常。隨之就程序結束了。我昨天在這個上吃了很多虧。因此需要注意的就是將文件夾中的文件複製到自己下的這兩個目錄之下就可以運行了。
C:\Windows\System32
C:\Windows\SysWOW64
以上,送給一個像我一樣,愛裝逼又愛折騰的你!