Tìm hiểu về Clang
Mở bài
Mình đang quá trình học C++
, tò mò nên tìm hiểu lại về các step khi chạy 1 chương trình thì có các steps:
- Preprocess
- Compile
- Translate to assembly code
- Translate to machine code
- Linking
Mình thử viết 1 chương trình hello world để test các bước trên. Thay vì sử dụng g++ -o index.o index.cpp
thì mình sử dụng make file như dưới đây để tìm hiểu về từng bước ở trên.
|
|
Ngoài trừ bước link
, các bước khác đều hoạt động như expected. Đến bước link
thì bắn ra lỗi sau:
1 2 3 4 5 |
Undefined symbols for architecture x86_64: "__Unwind_Resume", referenced from: __ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m in index.o __ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_ in index.o __ZNKSt3__19basic_iosIcNS_11char_traitsIcEEE5widenEc in index.o |
Clang
Vấn đề
Như thương lệ, search lỗi trên bác Google thì mình đổi phần link
trong make file thành như sau thì chạy thành công
|
|
Đến đây mình mới tò mò, là tại sao đổi từ ld
sang clang
thì lại chạy. ld
thì theo mình hiểu là tool để linking
rồi, thế thì clang
là cái giống gì? Nó khác gì với ld
?
Google nhanh với từ khoá clang vs ld
. -> Không ra kết quả gì khả thi. Chứng tỏ giả định của mình rằng 2 clang
để thay thế cho ld
có vẻ không đúng 100% và không bao quát toàn bộ vấn đề.
Tiếp tục 1 hồi lần mò trên internet, từ khái niệm này sang khái niệm khác. Thì cuối cùng dựa vào 2 link ở dưới, mình đã có thể trả lời được câu hỏi Clang
là gì?
Đáp án
Trả lời ngắn gọn thì: Clang là một compiler, tương tự như gcc compiler. Do đó không ngạc nhiên khi mình chuyển từ ld
sang clang
thì lại build được. Do câu lệnh clang
nó đã bao gồm cả quá trình linking rồi.
Điểm khác biệt giữa clang
và gcc
đó chính là clang
thì sử dụng LLVM IR (intermediate representation)
, trong khi đó gcc
thì sử dụng GIMPLE
Ref. Do đó clang
có thể tận dụng được các lợi thế của LLVM để compile ra các platform khác nhau 1 cách dễ dàng. Thậm chí có thể sử dụng LLVM IR
để chạy code C/C++
với nearly native perfomance trên web bằng cách sử dụng Emscripten convert LLVM IR
sang ngôn ngữ Webassembly
và sau đó nhúng vào web.
Bởi vì clang
sinh ra để thay thế gcc
, do đó nó cũng có đủ hết các step của compiler
như:
1 2 3 4 5 6 |
Preprocessor: This performs the actions of the C preprocessor: expanding #includes and #defines. The -E flag instructs Clang to stop after this step. Parsing: This parses and semantically analyzes the source language and builds a source-level intermediate representation (“AST”), producing a precompiled header (PCH), preamble, or precompiled module file (PCM), depending on the input. The -precompile flag instructs Clang to stop after this step. This is the default when the input is a header file. IR generation: This converts the source-level intermediate representation into an optimizer-specific intermediate representation (IR); for Clang, this is LLVM IR. The -emit-llvm flag instructs Clang to stop after this step. If combined with -S, Clang will produce textual LLVM IR; otherwise, it will produce LLVM IR bitcode. Compiler backend: This converts the intermediate representation into target-specific assembly code. The -S flag instructs Clang to stop after this step. Assembler: This converts target-specific assembly code into target-specific machine code object files. The -c flag instructs Clang to stop after this step. Linker: This combines multiple object files into a single image (either a shared object or an executable). |
Và có thể sử dụng flag -v
hoặc -###
khi chạy clang
để nhìn thấy câu lệnh của các steps trên khi chạy clang
. Ví dụ như ở bước Linker
, mình thêm -v
vào thì sẽ được output như sau:
1 2 3 4 5 6 |
clang -std=c++11 -stdlib=libc++ -lc++ -m64 -o index index.o -v Apple LLVM version 10.0.1 (clang-1001.0.46.4) Target: x86_64-apple-darwin18.5.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin "/Library/Developer/CommandLineTools/usr/bin/ld" -demangle -lto_library /Library/Developer/CommandLineTools/usr/lib/libLTO.dylib -dynamic -arch x86_64 -macosx_version_min 10.14.0 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -o index -lc++ index.o -L/usr/local/lib -lSystem /Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/lib/darwin/libclang_rt.osx.a |
Có thể thấy rõ ràng là clang
gọi đến ld
behind the scene, nhưng với 1 loạt các tham số. Đây là lý do mà câu lệnh ld
ở make file ban đầu của mình không chạy.
Với flag -###
, có thể thấy các output của các step còn lại như sau:
1 2 3 4 5 6 7 |
clang -std=c++11 -stdlib=libc++ -lc++ -m64 -o index index.cpp -### Apple LLVM version 10.0.1 (clang-1001.0.46.4) Target: x86_64-apple-darwin18.5.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin "/Library/Developer/CommandLineTools/usr/bin/clang" "-cc1" "-triple" "x86_64-apple-macosx10.14.0" "-Wdeprecated-objc-isa-usage" "-Werror=deprecated-objc-isa-usage" "-emit-obj" "-mrelax-all" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "index.cpp" "-mrelocation-model" "pic" "-pic-level" "2" "-mthread-model" "posix" "-mdisable-fp-elim" "-fno-strict-return" "-masm-verbose" "-munwind-tables" "-target-sdk-version=10.14" "-target-cpu" "penryn" "-dwarf-column-info" "-debugger-tuning=lldb" "-target-linker-version" "450.3" "-resource-dir" "/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1" "-isysroot" "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk" "-I/usr/local/include" "-stdlib=libc++" "-Wno-atomic-implicit-seq-cst" "-Wno-framework-include-private-from-public" "-Wno-atimport-in-framework-header" "-Wno-quoted-include-in-framework-header" "-std=c++11" "-fdeprecated-macro" "-fdebug-compilation-dir" "/Users/hs/Documents/workspace/test" "-ferror-limit" "19" "-fmessage-length" "134" "-stack-protector" "1" "-fblocks" "-fencode-extended-block-signature" "-fregister-global-dtors-with-atexit" "-fobjc-runtime=macosx-10.14.0" "-fcxx-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-o" "/var/folders/_v/s1ss70n55433z7rhsk2tnd3w0000gn/T/index-3d2ce5.o" "-x" "c++" "index.cpp" "/Library/Developer/CommandLineTools/usr/bin/ld" "-demangle" "-lto_library" "/Library/Developer/CommandLineTools/usr/lib/libLTO.dylib" "-no_deduplicate" "-dynamic" "-arch" "x86_64" "-macosx_version_min" "10.14.0" "-syslibroot" "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk" "-o" "index" "-lc++" "/var/folders/_v/s1ss70n55433z7rhsk2tnd3w0000gn/T/index-3d2ce5.o" "-L/usr/local/lib" "-lSystem" "/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/lib/darwin/libclang_rt.osx.a" |
Kết luận
Thực ra ban đầu bài blog này mình định viết để tìm hiểu về LLVM
, nhưng thông qua việc tìm hiểu về Clang
, vai trò của nó trong hệ sinh thái của LLVM
thì mình cũng hiểu được phần nào về LLVM
. Mong là sẽ có 1 lúc nào đó có thời gian để đào sâu hơn và có thể viết ra 1 toy compiler dựa trên LLVM
.
Ref
- https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
- https://bcain-llvm.readthedocs.io/projects/clang/en/latest/Toolchain/
- https://stackoverflow.com/questions/2354725/what-exactly-is-llvm
- https://en.wikipedia.org/wiki/Intermediate_representation
- http://www.aosabook.org/en/llvm.html
- https://www.infoworld.com/article/3247799/what-is-llvm-the-power-behind-swift-rust-clang-and-more.html
Author nhs000
LastMod 2021-03-06