C Language: The Relationship Between clangd, Clang, and GCC

This article discusses the relationship between clangd, Clang, and GCC through answers to various questions.

The Relationship Between clangd, Clang, and GCC

  1. Discuss the JIT compilation technology based on Intermediate Representation (IR), introducing the LLVM compilation chain/Clang frontend (compiler project) which is also based on IR.

  2. As a compiler striving to replace GNU/GCC, compare the similarities and differences between the two.

  3. Finally, provide the definition from the clangd official website, indicating that it is an “additional” tool project derived from LLVM.

C Language: The Relationship Between clangd, Clang, and GCC

01

JIT Compilation Based on Intermediate Representation (IR)

1.1 JIT Compilation

As a commonly confused comparison, we first introduce the concept of “Just-in-time compilation (JIT)”.

In the Chinese context, it seems there is no corresponding translation for “just-in-time (JIT)” (often awkwardly translated as “即时”). In the manufacturing field, it represents a form of “precise manufacturing” or “just-in-time manufacturing”. It means being very accurate and immediate, wasting no resources, arranging just the right amount of resources needed immediately.

In the compilation field, it serves as the core of “dynamic compilation/runtime compilation”, contrasting with the traditional “static compilation” model of C/C++ (which is also an “ahead-of-time compilation” model).

1.2 Dynamic Compilation Technology

Thus, “Just-in-time (JIT)” compilation, at execution time (runtime), compiles the program that is about to run in a timely manner. It is “compiling while running” and also “immediate compilation of the upcoming execution”.

It is “dynamic compilation” or “runtime compilation”.

Note: The parts that need to be executed immediately can be per file (depending on each file), per function, or even any code snippet.

1.3 Two Traditional Forms of Transpilation

“Static ahead-of-time compilation” (like traditional C/C++ compilation) and “(runtime, possibly line-by-line) interpretation” (like traditional interpreted languages such as Basic), thus, are perfectly integrated by “JIT compilation”.

JIT compilation first produces “Intermediate Representation (IR)” through “static ahead-of-time compilation”, and then at runtime, compiles this “Intermediate Representation (IR)” to generate per target machine code. In this way, JIT compilation combines the power of “static ahead-of-time compilation” with the flexibility of “runtime interpretation”.

Note: “IR” can also be interpreted purely, which would then have nothing to do with JIT compilation, but this is also a certain mode of application.

1.4 Java

Although JIT (compilation) technology has been around for a long time, Ken Thompson (the inventor of B language, the predecessor of C language) used it in an application regarding the runtime representation of regular expressions.

However, the actual application of JIT compilation technology can be considered to have officially started with the introduction of the JVM around 1994 (and the newly invented language Java). The Intermediate Representation (IR) in the JVM, i.e., the Java Virtual Machine, is compiled or interpreted in a dynamic, runtime manner.

Note: Correspondingly, there is MS’s .NET platform. Additionally, JIT technology has also been applied in later Python.

1.5 Features of Java (A Slightly Deeper Discussion)

  • Based on the above principles, it is easy to speculate that the potential problem brought by “JIT compilation” is the latency in running speed, i.e., reduced program performance (compared to pure traditional transpilation forms). A common solution is to cause delays only during the first run (the so-called “warm-up or pre-warm”), while subsequent runs load the program into memory, resulting in an “immediate acceleration” effect.

  • According to the aforementioned division of compilation into two stages and the introduction of a virtual machine (or virtual runtime platform) to perform IR immediate compilation, it undoubtedly increases more compilation methods and new features: such as selective optimization and garbage collection mechanisms. These are often mentioned as certain comparative advantages of Java.

1.6 The Original Intention and Popularity of Java

Thus, on the JVM platform, Java programs can cross different OS (whether Windows or Linux). This was both a necessity with the advent of the internet era in 2000 and possibly a rare commercial choice at the time, considering various factors, to reject MSVS’s C++.

According to some earlier readings, the design intention of Java/JVM (Java runtime environment)/JIT was aimed at all “hardware chip (instruction set) platforms”, intending to unify the intermediate environment (platform) on top of the chip (processor).

It can be seen that the objective development of Java has deviated from its original intention.

C Language: The Relationship Between clangd, Clang, and GCC

02

LLVM Compilation Chain Project Based on Intermediate Representation (IR)

2.1 The Association of the Abbreviation LLVM (Now Obsolete)

Similarly, LLVM seems to have also experienced a deviation from its original fate. LLVM originally meant “Low Level Virtual Machine”. Intuitively, this is almost a replica of the original intention of Java VM.

However, regardless of its original intention, the association of this abbreviation has been completely abandoned. After all, LLVM is now purely a collection of tools for the compilation chain (a so-called “umbrella” open-source project), thus differing from the VM/runtime environment introduced by JIT compilation.

The following quote is from the first paragraph of the LLVM official website.

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. Despite its name, LLVM has little to do with traditional virtual machines. The name “LLVM” itself is not an acronym; it is the full name of the project.

Note its emphasis, “Despite the name (which may be misleading), LLVM has nothing to do with traditional (conceptual) virtual machines (VM).”

2.2 Intermediate Representations (IR)

  1. From the perspective of “Intermediate Representation (IR)”, IR is the core of the entire JIT (two-stage compilation steps, where the former’s static compilation product IR is dynamically compiled at runtime to generate target machine code).

  2. For Java, this “Intermediate Representation (IR)” is bytecode (which is independent, allowing Java to be cross-platform).

  3. The interesting connection is that although LLVM does not have the mandatory content of JIT compilation (or JVM), the “Intermediate Representation (IR)” is also the conceptual core of the LLVM compilation chain (umbrella project).

2.3 Differences in LLVM/IR (LLVM’s IR is Language-Independent)

(1) The IR of JIT (i.e., bytecode) is not “human-readable source code”. It is encoded in compact numerical form, constants, references (usually numerically addressed), and the encoded results after compiler analysis. It represents types, (data types/functions) scopes, and the embedding depth of program objects, etc., as a manifestation of syntax analysis.

(2) Regarding “Intermediate Representation (IR)”, LLVM and JIT have diverged in their handling methods.

  • As mentioned earlier, JIT generates machine code for different targets through a “runtime environment” or “virtual machine (VM)”. It is “dynamic” or “runtime” compilation.

  • And as LLVM strives to distance itself from the beginner’s association with “VM”, it is no longer related to VM (platform execution-time compilation) but merely further compiles IR to generate more expressive machine code.

(3) An example of JIT’s IR (from wiki):

>>> import dis # "dis" - Disassembler of Python byte code into mnemonics. >>> dis.dis('print("Hello, World!")')  1  0  LOAD_NAME  0  (print)  2  LOAD_CONST  0  ('Hello,  World!')  4  CALL_FUNCTION  1  6  RETURN_VALUE 

(4) LLVM’s “Intermediate Representation (IR)” is defined as: a low-level programming language (similar to assembly).

Discussion: It seems that LLVM implements a certain pure compilation (chain) technology.

It decomposes the original static compilation process into two parts: first compiling “IR (RISC instruction set, low-level programming language similar to assembly)”, and then continuing the compilation process based on IR (producing machine code). This compilation of IR does not emphasize the need for a VM (a certain virtual independent platform) to achieve.

(5) LLVM’s IR can have three equivalent representations, including: (a) human-readable assembly format. (b) memory loading format adapted for the frontend. (c) compact bitcode format for serialization.

(6) An example of LLVM’s IR based on “Hello world”:

@.str = internal constant [14 x i8] c"hello, world\0A\00" declare i32 @printf(i8*, ...) define i32 @main(i32 %argc, i8** %argv) nounwind { entry: %tmp1 = getelementptr [14 x i8], [14 x i8]* @.str, i32 0, i32 0 %tmp2 = call i32 (i8*, ...) @printf( i8* %tmp1 ) nounwind ret i32 0 } 

2.4 Members of the LLVM Umbrella Structure

With the introduction of IR (low-level/assembly-like language), the members of the LLVM (compilation chain project) umbrella architecture can also be determined. They include:

(1) Frontend: (compilers for different languages)

Unlike JIT, the concept of JIT is usually accompanied by the learning of new programming languages such as Java/Python. The frontend of LLVM is almost entirely based on existing languages, new compilers (because LLVM appeared too late?).

Answering the question (Clang):

  1. Clang is a compiler, the frontend of LLVM (the umbrella open-source project for compiling C/C++, and since it is supported by Apple, it also supports compiling Objective-C/C++). Its status is almost equivalent to the traditional GNU’s gcc.

  2. However, unlike gcc, as mentioned earlier, clang produces “low-level, assembly-like” Intermediate Representation/IR (RISC).

  3. Additionally, a very important difference lies in the different licenses of the two (GPL vs. Apache License 2.0). Note: See below for details.

(2) Intermediate Representation/IR: strongly typed RISC instruction set.

(3) Backend: Translates IR (literal structure) into target machine code (through subprojects based on the LLVM umbrella project framework MC/Machine Code).

Discussion: Just like the easily confused JIT concept (which has a VM), here again appears the easily confused concept of “frontend/backend”.

  • In earlier platform development, “frontend” was commonly associated with the UI interface accessed by browsers (often seen in JavaScript development), while “backend” often referred to network HTTP servers. “Frontend” seems to give a sense of being “close to the target/user PC/user processor”.

  • However, in LLVM, the “frontend” is the “language compiler” (but programming languages are clearly more abstract). The component aimed at generating machine code becomes the “backend”.

  • The origin of this naming convention is unclear, and for the sake of efficient study, I did not search historical materials.

2.5 Different Licenses (Era Needs)

For commercial companies, continuously using GNU, or using its compilation chain GCC, seems unfeasible. Not to mention the wasted R&D investment (any modifications to the GPL copyrighted source code or any level of derivatives must be forced to be open-sourced), even considering security issues, it becomes quite tricky.

It can be speculated that there must exist geniuses or experts in the world who are different from ordinary people. The commercial open-source source code is like “fruit falling” in front of them. If there is any malicious intent, the company may face various dire consequences of commercial claims. Excluding closed loops like MS’s own MSVC compiler, other groups like Apple and Huawei can be imagined to have a pressing mentality.

In 2005, Apple hired LLVM’s inventor Lattner. Therefore, regardless of what LLVM’s original intention was, it is understood that it must have become what it is now — a compilation chain.

The earliest LLVM license was UIUC (the university where Lattner was), which is BSD-like. After v9.0.0, it became Apache License 2.0 (which seems slightly stricter than BSD, requiring copyright notices to be attached to modified files). Regardless of which, they all allow commercial closed-loop usage.

Now, whether it is new chip processor companies releasing new architectures (like the new RISC5), or even small teams releasing new compilers for academic or commercial purposes, as long as these products are based on open-source LLVM, they can be used commercially in a closed loop (without having to disclose any source code).

2.6 LLVM Does Not Restrict the Relocation Method of IR

The following quote is from Wiki:

LLVM can also generate relocatable machine code at compile-time or link-time or even binary machine code at run-time.

LLVM generates relocatable machine code, which can occur at compile-time, link-time, or even at runtime as binary machine code.

Here, it is understood that LLVM’s broad definition theoretically also covers existing JIT compilation technology. However, as mentioned above, LLVM’s emphasis has shifted to the following content: LLVM’s IR is language-independent, and LLVM’s “frontend” is based on (different) language compilers (used to generate independent Intermediate Representations/IR).

C Language: The Relationship Between clangd, Clang, and GCC

03

Clang Compiler

3.1 Clang Appeared Later in the LLVM Open Source Project

As a compiler chain striving to replace GCC in a drop-in manner (meaning “whenever you want, you can do it immediately, without appointment”), Clang appeared slightly later in the LLVM open-source project.

In Lattner’s LLVM framework, the early versions still had to use the proven C/C++ frontend LLVM-GCC (which Apple was still using until 2013). However, based on the aforementioned, it can be speculated that LLVM-GCC and GNU/GCC generate targets have completely different goals. LLVM-GCC must have been used by Lattner to analyze C/C++ source code and create (compile) the IR of the RISC instruction set (the assembly-like instruction set’s intermediate representation).

Clang’s formal use may have started around 2017/18 (see the brief summary below).

3.2 Advantages of Clang Compared to GCC

As LLVM/Clang appeared so late, it must possess certain advantages that are often described as “filling in the gaps”.

Answering the question (Comparison of Clang and GCC):

  • The entire design of LLVM/Clang is based on libraries, thus having high integration flexibility. This is an important reason for the implementation of OpenCL, CUDA, and other (modern AI-oriented) technologies.

  • Based on libraries (rather than GCC’s independent provision of the “compile-link-debug” workflow), Clang can provide better compilation error localization and better compilation error/warning prompts.

  • Thus, it also offers better (code editing assistance) features such as “syntax highlighting” or “autocomplete”.

  • Similarly, better (syntax) analysis trees and (better) support for “code refactoring”.

Discussion: As a tool in the compilation chain, it seems that there are no “disruptive” functional advancements? Is it mainly due to the necessity of choosing non-GPL? This is merely a speculation for reference.

3.3 Performance Comparison Between Clang and GCC

(1) Early Clang had astonishing improvements in memory usage and compilation speed compared to GCC. A comparison from 2007 showed that Clang was twice as fast while using only 1/6 of the memory.

(2) However, around 2016 to 2019, the performance gap between the two in compiling unoptimized C code became less significant, with each having its strengths and weaknesses.

(3) Besides the aforementioned “horizontal comparison” between Clang and GCC, there exists a “vertical comparison” among Clang’s own versions. A vertical comparison in 2021 indicated that as versions iterate, the time required for optimization becomes longer, while the execution speed of the compiled code becomes faster. For example, LLVM v11 took twice as long to compile compared to v2.7, but the execution speed of the compiled code improved by 10-20% (this data is from Wiki).

3.4 Important Milestones in Clang’s Development:

  • 23 October 2009, Clang 1.0 released, with LLVM 2.6 for the first time.

  • 2 February 2010, Clang self-hosting.

  • October 2016, Clang becomes the default compiler for Android.

  • 26 July 2017, Clang becomes the default compiler in OpenBSD 6.2 on amd64/i386.

  • 19 January 2018, Clang becomes the default compiler in OpenBSD 6.3 on arm.

  • 5 March 2018, Clang is now used to build Google Chrome for Windows. Mozilla made the same change for Firefox in September of the same year.

  • 19 September 2019, Clang 9.0.0 released with official RISC-V target support.

  • 29 February 2020, Clang becomes the only C compiler in the FreeBSD base system, with the removal of GCC.

It can be seen:

  1. The most steadfast supporter of Clang is FreeBSD.

  2. In 2016, Clang became the default compiler for Android, and in 2019, Clang supported RISC5.

  3. Notable products include Google Chrome from 2018 and Mozilla Firefox.

  4. Clang v3.8 supporting OpenMP is also an important milestone, noted here.

  5. C Language: The Relationship Between clangd, Clang, and GCC

    04

    clangd (Autocomplete) Tool

    4.1 clangd Comes from the LLVM Subproject (“clang-extra”)

    • On the latest download page (from the LLVM official website, checking the latest version 21.1.0, 2025.8), clangd belongs to the clang-extra subproject.

    • Although “clang-extra” and “clang” are distributed in a parallel relationship, functionally, clang-extra seems to include a series of “extra” tools provided for clang.

    • For example, “clang-tidy” (a static analysis tool), like clangd, also belongs to the “clang-extra” subproject.

    4.2 What is “clangd”?

    The following illustration comes from the clangd (LLVM official website) homepage:

    C Language: The Relationship Between clangd, Clang, and GCC

    Answering the question (clangd is Clang’s “code completion” tool, integrated into IDE as a “language server”):

    1. clangd is an “extra” (code completion) tool of the frontend Clang (C/C++ compiler) project of the LLVM (compilation chain open-source project collection).

    2. Thus, clangd is based on the “frontend” Clang C++ compiler and belongs to the LLVM project (clang-extra).

    3. clangd analyzes C/C++ code and implements “smart” features (commonly used in code editing), including: code completion, compilation errors, definition (cross-reference) jumps, symbol navigation, tooltip (hover hint bar), unified formatting (aesthetic), code refactoring, syntax highlighting, etc. clangd can be integrated into IDEs as a plugin.

    4. Unlike traditional compiler autocompletion, clangd’s technical role is as a “language server”, usable across different (IDE) editors.

    Note: The illustration shows an example of clangd as a plugin integrated into VSCode (the features displayed are merely traditional “code completion” functionalities).

    4.3 LSP (Language Server Protocol)

    As previously explained, clangd’s implementation of “code completion” technology differs from traditional methods. clangd serves as a “language server” for the IDE’s Editor.

    The clangd official webpage indicates knowledge jumps regarding LSP:

    C Language: The Relationship Between clangd, Clang, and GCC

    Jumping to the GitHub page of the “LSP” project, it explains the definition of “LSP (Language Server Protocol)”:

    C Language: The Relationship Between clangd, Clang, and GCC

    A Language Server is meant to provide the language-specific smarts and communicate with development tools over a protocol that enables inter-process communication.

    Language servers mean providing “language-specific” smart features, communicating with IDEs (and that server) over a protocol that enables inter-process communication.

    Here, it is understood that for a specific language, an autocomplete plugin based on LSP can be integrated into different IDEs, allowing the same “language (smart features) server” to be used without each different IDE needing to develop separately using different APIs.

    So, can clangd based on Clang “navigate” across different IDEs? It seems not entirely, because Clang is an open-source project, and LSP (as well as its protocol LSIF) is an open protocol, which may also have different LSP projects.

    For example:

    C Language: The Relationship Between clangd, Clang, and GCC

    4.4 Checking clangd’s Version

    The question is “clang –version does not exist, but gcc does exist”.

    If the question is about checking the version of “clangd”, since I have not installed the clangd plugin in VSCode, I cannot provide practical experience. However, similar questions are answered in clangd’s FAQ:

    C Language: The Relationship Between clangd, Clang, and GCC

    Answering the question: To check the version of clangd, either look in the output window (panel) of the integrated IDE (in this example, VSCode), or use the command clangd –version in the compiler path. However, as indicated in the image above, since clangd often exists as a plugin in various IDEs, the standalone console program of clangd may not be the same as the one used in the IDE.

    If the question is about the Clang version, then check whether LLVM is pre-installed by default (for example, in MacOS), or review the installation process.

Leave a Comment