C++的編譯鏈接與在vs中build提速

通過gcc或msvc,clang等編譯器編譯出來的C++源文件是.o文件。在windows上也就是PE文件,linux爲ELF文件,在這一步中,調用其它代碼文件中的函數的函數地址是未知的(00000),等到鏈接之後纔會替換掉函數地址的

linux,windows 可執行文件(ELF、PE)

C++是如何編譯的

C/C++編譯過程主要分爲4個過程

  1. 編譯預處理
  2. 編譯、優化階段
  3. 彙編過程
  4. 鏈接程序

image-20230829161222197

編譯遊戲引擎的耗時

內網使用IB(incrediBuild)編譯引擎時總耗時2分23秒,編譯2分鐘,link耗時15秒

在vs中提高c++的編譯速度

達到修改一行代碼,10s內編譯完,link會花點時間,因爲所的工程都是lib,而不是dll,如果改成dll,則會更快。

調試信息的格式

把所有的工程的屬性這項: C/C++ - General - Debug Information Format ,改成:C7 compatible (/Z7)

實際上是在vcxproj文件中增加了這樣一項:<DebugInformationFormat>OldStyle</DebugInformationFormat>

Debug Information Format是一個編譯器選項,用於控制生成的調試信息的格式。

調試信息是一種用於調試程序的數據,包括變量名、函數名、行號等信息。在程序出現錯誤時,調試信息可以幫助開發人員快速定位問題。

Debug Information Format選項有以下幾種可選值:

  1. None:不生成調試信息。

  2. Program Database (/Zi):生成一個獨立的PDB文件,包含所有的調試信息。

  3. Program Database for Edit and Continue (/ZI):生成一個獨立的PDB文件,包含所有的調試信息,並且支持編輯和繼續調試。

  4. Old Style (/Z7):將調試信息嵌入到可執行文件中。

需要注意的是,生成調試信息會增加可執行文件的大小,因此在發佈版本時應該關閉調試信息生成。

另外,需要注意的是,如果使用了/DEBUG選項,那麼編譯器會自動將Debug Information Format選項設置爲Program Database (/Zi)。

預編譯頭

選中工程,右鍵 - 屬性 - C/C++ - Precompiled Headers - Precompiled Header 改成 Not

就是把一些固定的東西先編譯好,其他cpp文件直接引用就不copy了,這東西在分佈式下沒用, 單機是有效果的

什麼是預編譯頭?

includeN多的頭文件會導致編譯變慢,提取整個項目公共頭文件放到一起,只編譯一次,減少編譯時間。

增量編譯

在入口工程啓用增量編譯 : Linker - General - Enable Incremental Linking,勾選:Yes (/INCREMENTAL)

Linker - Optimization

右鍵 - 屬性,Linker - Optimization - 把這2項改成No

  • References :No (/OPT:NOREF)
  • Enable COMDAT Folding :No (/OPT:NOICE)

OptimizeReferences 用於控制是否優化未使用的函數和數據的代碼生成,當OptimizeReferences選項設置爲/OPT:REF時,編譯器將在鏈接時刪除未使用的函數和數據,以減小可執行文件的大小。這可以減少可執行文件的大小,提高程序的運行效率。

EnableCOMDATFolding 用於控制是否啓用COMDAT摺疊優化,當Enable COMDAT Folding選項設置爲Yes/OPT:ICF時,編譯器將啓用COMDAT摺疊優化。這可以減少可執行文件的大小,提高程序的運行效率。

Linker - Debugging

右鍵 - 屬性, Linker - Debugging , Generate Debug Info 改成Faster,可以link的更快

cgthreads(Code generation threads)

cl 默認使用的線程數是 4 ,最大可設置成 8 ,如果擁有更多核心時設置爲8將可以縮短構建時間,在開啓GL時效果更佳

在項目 配置屬性 > C/C++ > 命令行 增加 /cgthreads8

MP(Build with multiple processes)

當您編譯許多文件時,編譯器選項可以顯着減少構建時間。爲了縮短構建時間,編譯器會創建最多processMax自身的副本,然後同時使用這些副本來編譯源文件

其他模式建議開啓, published 模式 , 測試後構建時間並無明顯差異, 因爲MP對鏈接時編譯並不能起到提速作用

同樣也是在項目 配置屬性 > C/C++ > 命令行 增加 /mp

Incredibuild(集羣編譯)

使用ib編譯完之後,再從vs按F5即可啓動調試,已經生成了pdb文件。

非published模式(非WPO模式) 建議以下設置:

打開IB,切到Visual Studio Builds - Advanced

  1. 關閉 Limit Concurrent PDB file Instances to []
  2. 開啓 Force 64-bit tooset

使用集羣或者限制本機cpu的核數,這倆動態控制好,但是本機使用一半的核還是會卡,因爲其它進程不一定會分配到空閒的CPU

打開IB,切到Initiator - General

  1. Avoid task execution on local machine when possible(儘可能避免在本地計算機上執行任務)

  2. CPU Allocation : Limit maximum number of cores utilized in build to (限制構建過程中可使用的最大核心數爲)

WPO

全程序優化(Whole program optimization) 功能,是爲了增加文件之間的可見性,將編譯延遲到了鏈接時

WPO 可以提高程序的執行性能,一般在發佈模式下都會開啓此功能,代價只是增加了部分構建時長

如果開啓WPO模式後, 不建議使用 IB 構建, 也許可能會有未知問題

makefile

摘自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

cmake.txt示例

cmake_minimum_required(VERSION 3.17)
project(mycpp)

set(CMAKE_CXX_STANDARD 11)
#添加需要編譯的文件
add_executable(strTest strTest.cpp)

C/C++爲什麼要寫頭文件?

來源: 爲什麼C/C++要分爲頭文件和源文件? - 知乎 (zhihu.com)

C時代的時候編譯器比較簡單,是固定的編譯和鏈接兩個過程,編譯一次只處理一個文件,進行預處理之後,頭文件會插入到這一個文件裏,不同源代碼文件的處理時獨立的,這樣如果頭文件裏面定義了一個函數的實現,編譯的時候所有引用這個頭文件的源碼文件,生成的obj裏都會有這個符號。而鏈接是通用的鏈接程序,從彙編時代就用的工具,沒有什麼高級功能,同一個符號鏈接時出現兩次是會報錯的。

但是,我們又說了,每個文件的編譯是獨立的,所以如果實現不在當前源文件裏面,調用的時候編譯器就不知道這個函數的類型和簽名,沒法生成調用代碼,所以必須在調用之前先聲明一遍。如果不把聲明寫在頭文件裏面,就必須在每個用到這個函數的源文件裏都聲明一遍,很不方便,所以綜合之後的解決方案就是實現寫源碼文件裏面,聲明寫頭文件裏面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章