通過gcc或msvc,clang等編譯器編譯出來的C++原始檔是.o檔案。在windows上也就是PE檔案,linux為ELF檔案,在這一步中,呼叫其它程式碼檔案中的函數的函數地址是未知的(00000),等到連結之後才會替換掉函數地址的
C/C++編譯過程主要分為4個過程
內網使用IB(incrediBuild)編譯引擎時總耗時2分23秒,編譯2分鐘,link耗時15秒
達到修改一行程式碼,10s內編譯完,link會花點時間,因為所的工程都是lib,而不是dll,如果改成dll,則會更快。
把所有的工程的屬性這項: C/C++ - General - Debug Information Format ,改成:C7 compatible (/Z7)
實際上是在vcxproj檔案中增加了這樣一項:<DebugInformationFormat>OldStyle</DebugInformationFormat>
Debug Information Format是一個編譯器選項,用於控制生成的偵錯資訊的格式。
偵錯資訊是一種用於偵錯程式的資料,包括變數名、函數名、行號等資訊。在程式出現錯誤時,偵錯資訊可以幫助開發人員快速定位問題。
Debug Information Format選項有以下幾種可選值:
None:不生成偵錯資訊。
Program Database (/Zi):生成一個獨立的PDB檔案,包含所有的偵錯資訊。
Program Database for Edit and Continue (/ZI):生成一個獨立的PDB檔案,包含所有的偵錯資訊,並且支援編輯和繼續偵錯。
Old Style (/Z7):將偵錯資訊嵌入到可執行檔案中。
需要注意的是,生成偵錯資訊會增加可執行檔案的大小,因此在釋出版本時應該關閉偵錯資訊生成。
另外,需要注意的是,如果使用了/DEBUG選項,那麼編譯器會自動將Debug Information Format選項設定為Program Database (/Zi)。
選中工程,右鍵 - 屬性 - C/C++ - Precompiled Headers - Precompiled Header 改成 Not
就是把一些固定的東西先編譯好,其他cpp檔案直接參照就不copy了,這東西在分散式下沒用, 單機是有效果的
什麼是預編譯頭?
在入口工程啟用增量編譯 : Linker - General - Enable Incremental Linking,勾選:Yes (/INCREMENTAL)
右鍵 - 屬性,Linker - Optimization - 把這2項改成No
OptimizeReferences 用於控制是否優化未使用的函數和資料的程式碼生成,當OptimizeReferences選項設定為/OPT:REF時,編譯器將在連結時刪除未使用的函數和資料,以減小可執行檔案的大小。這可以減少可執行檔案的大小,提高程式的執行效率。
EnableCOMDATFolding 用於控制是否啟用COMDAT摺疊優化,當Enable COMDAT Folding選項設定為Yes/OPT:ICF時,編譯器將啟用COMDAT摺疊優化。這可以減少可執行檔案的大小,提高程式的執行效率。
右鍵 - 屬性, Linker - Debugging , Generate Debug Info 改成Faster,可以link的更快
cl 預設使用的執行緒數是 4 ,最大可設定成 8 ,如果擁有更多核心時設定為8將可以縮短構建時間,在開啟GL時效果更佳
在專案 設定屬性 > C/C++ > 命令列 增加 /cgthreads8
當您編譯許多檔案時,編譯器選項可以顯著減少構建時間。為了縮短構建時間,編譯器會建立最多processMax自身的副本,然後同時使用這些副本來編譯原始檔
其他模式建議開啟, published 模式 , 測試後構建時間並無明顯差異, 因為MP對連結時編譯並不能起到提速作用
同樣也是在專案 設定屬性 > C/C++ > 命令列 增加 /mp
使用ib編譯完之後,再從vs按F5即可啟動偵錯,已經生成了pdb檔案。
非published模式(非WPO模式) 建議以下設定:
開啟IB,切到Visual Studio Builds - Advanced
使用叢集或者限制本機cpu的核數,這倆動態控制好,但是本機使用一半的核還是會卡,因為其它程序不一定會分配到空閒的CPU
開啟IB,切到Initiator - General
Avoid task execution on local machine when possible(儘可能避免在本地計算機上執行任務)
CPU Allocation : Limit maximum number of cores utilized in build to (限制構建過程中可使用的最大核心數為)
全程式優化(Whole program optimization) 功能,是為了增加檔案之間的可見性,將編譯延遲到了連結時
WPO 可以提高程式的執行效能,一般在釋出模式下都會開啟此功能,代價只是增加了部分構建時長
如果開啟WPO模式後, 不建議使用 IB 構建, 也許可能會有未知問題
摘自UE引擎的某個makefile範例
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wcast-align -Wcast-qual -Wno-ctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wno-float-equal
CPPFLAGS += -I ../single_include -I . -I thirdparty/doctest -I thirdparty/fifo_map -DDOCTEST_CONFIG_SUPER_FAST_ASSERTS
SOURCES = src/unit.cpp \
src/unit-algorithms.cpp \
OBJECTS = $(SOURCES:.cpp=.o)
TESTCASES = $(patsubst src/unit-%.cpp,test-%,$(wildcard src/unit-*.cpp))
cmake.txt範例
cmake_minimum_required(VERSION 3.17)
project(mycpp)
set(CMAKE_CXX_STANDARD 11)
#新增需要編譯的檔案
add_executable(strTest strTest.cpp)
來源: 為什麼C/C++要分為標頭檔案和原始檔? - 知乎 (zhihu.com)
C時代的時候編譯器比較簡單,是固定的編譯和連結兩個過程,編譯一次只處理一個檔案,進行預處理之後,標頭檔案會插入到這一個檔案裡,不同原始碼檔案的處理時獨立的,這樣如果標頭檔案裡面定義了一個函數的實現,編譯的時候所有參照這個標頭檔案的原始碼檔案,生成的obj裡都會有這個符號。而連結是通用的連結程式,從組合時代就用的工具,沒有什麼高階功能,同一個符號連結時出現兩次是會報錯的。
但是,我們又說了,每個檔案的編譯是獨立的,所以如果實現不在當前原始檔裡面,呼叫的時候編譯器就不知道這個函數的型別和簽名,沒法生成呼叫程式碼,所以必須在呼叫之前先宣告一遍。如果不把宣告寫在標頭檔案裡面,就必須在每個用到這個函數的原始檔裡都宣告一遍,很不方便,所以綜合之後的解決方案就是實現寫原始碼檔案裡面,宣告寫標頭檔案裡面。