當前位置:編程學習大全網 - 源碼下載 - 如何使用ninja快速編譯LLVM和Clang

如何使用ninja快速編譯LLVM和Clang

1,Build llvm/clang/lldb/lld 3.5.0等組件

1.0 準備:

至少需要從llvm.org下載llvm, cfe, lldb, compiler-rt,lld等3.5.0版本的代碼。

$tar xf llvm-3.5.0.src.tar.gz

$cd llvm-3.5.0.src

$mkdir -p tools/clang

$mkdir -p tools/clang/tools/extra

$mkdir -p tools/lld

$mkdir -p projects/compiler-rt

$tar xf cfe-3.5.0.src.tar.xz -C tools/clang --strip-components=1

$tar xf compiler-rt-3.5.0.src.tar.xz -C projects/compiler-rt --strip-components=1

$tar xf lldb-3.5.0.src.tar.xz -C tools/clang/tools/extra --strip-components=1

$tar xf lld-3.5.0.src.tar.xz -C tools/lld --strip-components=1

1.1 可選使用clang --stdlib=libc++時,自動添加-lc++abi。

libc++組件可以使用gcc libstdc++的supc++ ABI,也可以使用c++abi,cxxrt等,實際上自動添加-lc++abi是不必要的,這裏這麽處理,主要是為了方便起見。實際上完全可以在“clang++ -stdlib=libc++”時再手工添加-lc++abi給鏈接器。

這裏涉及到鏈接時DSO隱式還是顯式的問題,早些時候ld在鏈接庫時會自動引入由庫引入的依賴動態庫,後來因為這個行為的不可控性,所以ld鏈接器的行為做了修改,需要顯式的寫明所有需要鏈接的動態庫,才會有手工添加-lc++abi這種情況出現。

--- llvm-3.0.src/tools/clang/lib/Driver/ToolChain.cpp 2012-03-26 18:49:06.663029075 +0800

+++ llvm-3.0.srcn/tools/clang/lib/Driver/ToolChain.cpp 2012-03-26 19:36:04.260071355 +0800

@@ -251,6 +251,7 @@

switch (Type) {

case ToolChain::CST_Libcxx:

CmdArgs.push_back("-lc++");

+ CmdArgs.push_back("-lc++abi");

break;

case ToolChain::CST_Libstdcxx:

1.2 必要給clang++添加-fnolibgcc開關。

這個開關主要用來控制是否連接到libgcc或者libunwind。

註:libgcc不等於libunwind。libgcc_eh以及supc++的壹部分跟libunwind功能相當。

註:libgcc_s和compiler_rt的壹部分相當。

這個補丁是必要的, 不會對clang的正常使用造成任何影響 ,只有在使用“-fnolibgcc"參數時才會起作用。

之所以進行了很多unwind的引入,主要是為了避免不必要的符號缺失麻煩,這裏的處理相對來說是幹凈的,通過as-needed規避了不必要的引入。

--- llvm-static-3.5.0.bak/tools/clang/lib/Driver/Tools.cpp 2014-09-10 13:46:02.581543888 +0800

+++ llvm-static-3.5.0/tools/clang/lib/Driver/Tools.cpp 2014-09-10 16:03:37.559019321 +0800

@@ -2060,9 +2060,15 @@

".a");

CmdArgs.push_back(Args.MakeArgString(LibClangRT));

- CmdArgs.push_back("-lgcc_s");

- if (TC.getDriver().CCCIsCXX())

- CmdArgs.push_back("-lgcc_eh");

+ if (Args.hasArg(options::OPT_fnolibgcc)) {

+ CmdArgs.push_back("--as-needed");

+ CmdArgs.push_back("-lunwind");

+ CmdArgs.push_back("--no-as-needed");

+ } else {

+ CmdArgs.push_back("-lgcc_s");

+ if (TC.getDriver().CCCIsCXX())

+ CmdArgs.push_back("-lgcc_eh");

+ }

}

static void addProfileRT(

@@ -7150,24 +7156,50 @@

bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;

bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||

Args.hasArg(options::OPT_static);

+

+

+

if (!D.CCCIsCXX())

- CmdArgs.push_back("-lgcc");

+ if (Args.hasArg(options::OPT_fnolibgcc)) {

+ CmdArgs.push_back("--as-needed");

+ CmdArgs.push_back("-lunwind");

+ CmdArgs.push_back("--no-as-needed");

+ } else

+ CmdArgs.push_back("-lgcc");

if (StaticLibgcc || isAndroid) {

if (D.CCCIsCXX())

- CmdArgs.push_back("-lgcc");

+ if (Args.hasArg(options::OPT_fnolibgcc)) {

+ CmdArgs.push_back("--as-needed");

+ CmdArgs.push_back("-lunwind");

+ CmdArgs.push_back("--no-as-needed");

+ } else

+ CmdArgs.push_back("-lgcc");

} else {

if (!D.CCCIsCXX())

CmdArgs.push_back("--as-needed");

- CmdArgs.push_back("-lgcc_s");

+ if (Args.hasArg(options::OPT_fnolibgcc))

+ CmdArgs.push_back("-lunwind");

+ else

+ CmdArgs.push_back("-lgcc_s");

if (!D.CCCIsCXX())

CmdArgs.push_back("--no-as-needed");

}

if (StaticLibgcc && !isAndroid)

- CmdArgs.push_back("-lgcc_eh");

+ if (Args.hasArg(options::OPT_fnolibgcc)) {

+ CmdArgs.push_back("--as-needed");

+ CmdArgs.push_back("-lunwind");

+ CmdArgs.push_back("--no-as-needed");

+ } else

+ CmdArgs.push_back("-lgcc_eh");

else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())

- CmdArgs.push_back("-lgcc");

+ if (Args.hasArg(options::OPT_fnolibgcc)) {

+ CmdArgs.push_back("--as-needed");

+ CmdArgs.push_back("-lunwind");

+ CmdArgs.push_back("--no-as-needed");

+ } else

+ CmdArgs.push_back("-lgcc");

// According to Android ABI, we have to link with libdl if we are

// linking with non-static libgcc.

--- llvm-static-3.5.0.bak/tools/clang/include/clang/Driver/Options.td 2014-08-07 12:51:51.000000000 +0800

+++ llvm-static-3.5.0/tools/clang/include/clang/Driver/Options.td 2014-09-10 13:36:34.598511176 +0800

@@ -788,6 +788,7 @@

def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;

def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;

def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>, Flags<[CC1Option]>;

+def fnolibgcc : Flag<["-"], "fnolibgcc">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;

def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;

def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;

def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;

1.3 llvm的其他補丁。

llvm/clang將gcc toolchain的路徑hard code在代碼中,請查閱tools/clang/lib/Driver/ToolChains.cpp。

找到x86_64-redhat-linux之類的字符串。

如果沒有妳系統特有的gcc tripple string,請自行添加。

這個tripple string主要是給llvm/clang搜索gcc頭文件等使用的,不影響本文要構建的toolchain

1.4 構建clang/llvm/lldb

本文使用ninja。順便說壹下,llvm支持configure和cmake兩種構建方式。可能是因為工程太大,這兩種構建方式的工程文件都有各種缺陷(主要表現在開關選項上,比如configure有,但是cmake卻沒有等)。llvm-3.4.1就是因為cmake工程文件的錯誤而導致了3.4.2版本的發布。

綜合而言,cmake+ninja的方式是目前最快的構建方式之壹,可以將構建時間縮短壹半以上。

mkdir build

cd build

cmake \

-G Ninja \

-DCMAKE_INSTALL_PREFIX=/usr \

-DCMAKE_BUILD_TYPE="Release" \

-DCMAKE_CXX_FLAGS="-std=c++11" \

-DBUILD_SHARED_LIBS=OFF \

-DLLVM_ENABLE_PIC=ON \

-DLLVM_TARGETS_TO_BUILD="all" \

-DCLANG_VENDOR="MyOS" ..

ninja

ninja install

如果系統原來就有clang/clang++的可用版本,可以添加:

-DCMAKE_C_COMPILER=clang \

-DCMAKE_CXX_COMPILER=clang++ \

這樣就會使用系統的clang++來構建llvm/clang

2,測試clang/clang++。

自己找幾個簡單的c/cpp/objc等編譯測試壹下即可。完整測試可以在構建時作ninja check-all

3,libunwind/libc++/libc++abi,壹套不依賴libgcc, libstdc++的c++運行庫。

3.1 從/pathscale/libunwind 獲取代碼。

libunwind有很多個實現,比如gnu的libunwind, path64的libunwind,還有libcxxabi自帶的Unwinder.

這裏作下說明:

1),gnu的libunwind會有符號缺失和沖突。

2),libcxxabi自帶的Unwinder是給mac和ios用的,也就是只能在darwin體系構建。目前Linux的實現仍然不全,等linux實現完整了或許就不再需要path64的unwind實現了。

暫時建議使用pathscale的unwind實現。

mkdir -p build

cd build

cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS="-m64" ..

ninja

mkdir -p /usr/lib

cp src/libunwind.so /usr/lib

cp src/libunwind.a /usr/lib

3.2 第壹次構建libcxx.

必須先構建壹次libcxx,以便後面構建libcxxabi。這裏構建的libcxx實際上是使用gcc的libgcc/stdc++/supc++的。

打上這個補丁來禁止libgcc的引入:

diff -Nur libcxx/cmake/config-ix.cmake libcxxn/cmake/config-ix.cmake

--- libcxx/cmake/config-ix.cmake 2014-06-25 06:57:50.000000000 +0800

+++ libcxxn/cmake/config-ix.cmake 2014-06-25 09:05:24.980350544 +0800

@@ -28,5 +28,4 @@

check_library_exists(c printf "" LIBCXX_HAS_C_LIB)

check_library_exists(m ccos "" LIBCXX_HAS_M_LIB)

check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)

-check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXX_HAS_GCC_S_LIB)

編譯安裝:

mkdir build

cd build

cmake \

-G Ninja \

-DCMAKE_INSTALL_PREFIX=/usr \

-DCMAKE_C_COMPILER=clang \

-DCMAKE_CXX_COMPILER=clang++ \

..

ninja

ninja install

3.3,測試第壹次構建的libcxx。

使用"clang++ -stdlib=libc++ -o test test.cpp -lstdc++"編譯簡單c++代碼,檢查是否出錯。(如果前面構建clang是已經apply了c++abi的鏈接補丁,這裏會出現找不到c++abi的情況,跳過即可)

使用"ldd test"查看test二進制動態庫使用情況。可以發現,test依賴於libgcc_s/libc++/libstdc++。(多少有些不爽了吧?使用了libc++居然還要依賴libstdc++?)

  • 上一篇:最豐富的5個源代碼
  • 下一篇:netty channelgroup的廣播信息,channel怎樣獲取
  • copyright 2024編程學習大全網