Compiling process of C/C + + program

preface

How does C/C + + code become a program that can run on hardware? Let's start with a simple "Hello World" program.

Hello World compilation

There is a popular joke:

A programmer was very interested in calligraphy and decided to make achievements in this field after retirement. So he spent a lot of money to buy the first-class four treasures of study. One day, after dinner, he suddenly had an elegant mood, polished ink and paper, and lit a good sandalwood, which was quite Wang Xizhi's style and Yan Zhenqing's momentum. He calmed down for a moment, splashed ink and wrote solemnly: Hello World

"Hello World" of C code, helloWorld.c As follows:

/*include head file*/
#include <stdio.h>

/*the main function*/
int main(int argc,char *argv[])
{
    printf("Hello World!\n");
    return 0 ;
}

Let's compile using gcc first:

$ gcc helloWorld.c 
$ ./a.out 
Hello World!

You can see, "Hello World!" Has been printed directly to the screen. So what happened here?

For help, we can run gcc --help to view the help instructions, one of which is:

-v         Display the programs invoked by the compiler.

In other words, adding the - v parameter can display the details of the program compiled and called. For more analysis of gcc -v, please refer to: Parsing gcc -v output

The output information is as follows:

$ gcc helloWorld.c -o helloWorld -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Uos 8.3.0.3-3+rebuild' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 8.3.0 (Uos 8.3.0.3-3+rebuild) 
COLLECT_GCC_OPTIONS='-o' 'helloWorld' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/8/cc1 -quiet -v -imultiarch x86_64-linux-gnu helloWorld.c -quiet -dumpbase helloWorld.c -mtune=generic -march=x86-64 -auxbase helloWorld -version -o /tmp/ccfIwQTj.s
GNU C17 (Uos 8.3.0.3-3+rebuild) version 8.3.0 (x86_64-linux-gnu)
        compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C17 (Uos 8.3.0.3-3+rebuild) version 8.3.0 (x86_64-linux-gnu)
        compiled by GNU C version 8.3.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.20-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: b0aa96b3fb90562a90ec754591a6a020
COLLECT_GCC_OPTIONS='-o' 'helloWorld' '-v' '-mtune=generic' '-march=x86-64'
 as -v --64 -o /tmp/ccUwhs9h.o /tmp/ccfIwQTj.s
GNU assembler version 2.31.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Uos) 2.31.1
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'helloWorld' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/8/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper -plugin-opt=-fresolution=/tmp/ccXGG9qg.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o helloWorld /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/8/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/8/../../.. /tmp/ccUwhs9h.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/8/crtend.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-o' 'helloWorld' '-v' '-mtune=generic' '-march=x86-64'

There is too much information. Let's digest it and eliminate the additional information. We can see three steps cc1, as and collect2, as follows:

Preprocessing and compiling cc1

Search this message for HelloWorld c. You will see:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -quiet -v -imultiarch x86_64-linux-gnu helloWorld.c -quiet -dumpbase helloWorld.c -mtune=generic -march=x86-64 -auxbase helloWorld -version -o /tmp/ccfIwQTj.s

As you can see, cc1 is used to convert HelloWorld C compile and generate ccfiwqtj s.

Assembly as

Continue to find ccfiwqtj s. You will see:

as -v --64 -o /tmp/ccUwhs9h.o /tmp/ccfIwQTj.s

as can be seen from it, ccfiwqtj S assembly generates ccfiwqtj o.

Link collect2

Continue to find ccfiwqtj o. You will see:

/usr/lib/gcc/x86_64-linux-gnu/8/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/8/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/8/lto-wrapper -plugin-opt=-fresolution=/tmp/ccXGG9qg.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o helloWorld /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/8/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/8 -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/8/../../.. /tmp/ccUwhs9h.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/8/crtend.o /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/crtn.o

As you can see, using collect2, ccuwhs9h O links with many other files to generate helloWorld.

Episode

The compilation process can be roughly divided into four steps: preprocessing, compilation, assembly and linking. But we have found that gcc -v only uses three steps. What's going on here?

stay Behind GCC compilation (preprocessing and compilation, assembly and linking) It is mentioned in:

In fact, gcc calls cpp here (although we only see CC1 through gcc's - v). cpp, The C Preprocessor, is mainly used to preprocess macro definitions, file inclusion, conditional compilation, etc.

Let's use cpp to test, and also add "- v" parameter:

$ cpp helloWorld.c -o helloWorld.i -v
Using built-in specs.
COLLECT_GCC=cpp
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Uos 8.3.0.3-3+rebuild' --with-bugurl=file:///usr/share/doc/gcc-8/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-8 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 8.3.0 (Uos 8.3.0.3-3+rebuild) 
COLLECT_GCC_OPTIONS='-E' '-o' 'helloWorld.i' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu helloWorld.c -o helloWorld.i -mtune=generic -march=x86-64
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/8/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/8/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-E' '-o' 'helloWorld.i' '-v' '-mtune=generic' '-march=x86-64'

It is found that cc1:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu helloWorld.c -o helloWorld.i -mtune=generic -march=x86-64

And HelloWorld C to compile and generate cfiwqtj S comparison:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -quiet -v -imultiarch x86_64-linux-gnu helloWorld.c -quiet -dumpbase helloWorld.c -mtune=generic -march=x86-64 -auxbase helloWorld -version -o /tmp/ccfIwQTj.s

It can be seen that cc1 adds the - E parameter during preprocessing. It can be understood that when cc1 adds the - E parameter, only preprocessing is performed. When cc1 does not add the - E parameter, preprocessing and compilation are completed at the same time. Therefore, there are only three steps, but preprocessing and compilation are combined into one step by cc1.

Four steps

Next, let's break down these four steps again and control each process with simpler parameters. Reference article: How is the hello program compiled?.

Tip: if the "- v" parameter is added to the following commands, you can also view the specific called programs and parameters, which is the decomposition of the previous steps.

Pretreatment

Preprocessing is mainly used to process the instructions starting with # in the source code (#pragma exception), such as #include in the hello world program in this article. After preprocessing, stdio The contents of H are inserted into the position of the preprocessing instruction.
To generate only the preprocessed content, GCC - E - O HelloWorld i helloWorld. C is equivalent to CPP - O HelloWorld i helloWorld. c:

gcc -E -o helloWorld.i helloWorld.c     # -The E parameter indicates that only preprocessing is performed

Generated HelloWorld I is the content after preprocessing. If you are interested, you can open the file to view the content, and you will find stdio The position of H is replaced by its actual content. After preprocessing, the comment content will also be deleted and the macro definition will be expanded.

After knowing this skill, we can preprocess some complex macro definitions and then view the preprocessed code to quickly troubleshoot and understand the code.

compile

After preprocessing, it is necessary to perform lexical analysis, syntax analysis and semantic analysis on the generated preprocessing files, and finally generate assembly code files. White dots can be simply understood as "translating" C code into assembly code. This process is not only the core, but also a more complex process. We can command:

gcc -S -o helloWorld.s helloWorld.c     # -The S parameter indicates that only until the assembly is generated

The generated assembly code HelloWorld S as follows:

        .file   "helloWorld.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello World!"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        movl    $.LC0, %edi
        call    puts
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Uos 8.3.0.3-3+rebuild) 8.3.0"
        .section        .note.GNU-stack,"",@progbits

assembly

Assembly is to translate assembly code into machine executable instructions and generate object files. The whole process is relatively simple, which is almost translated one by one according to assembly instructions and machine instructions. We can obtain the compiled content with the following command:

gcc -c -o helloWorld.o helloWorld.c     # -The c parameter indicates that only the executable instruction files of the machine are generated and are not linked

link

Link is to put all the target files together in some way to generate the final executable file. The printf function is invoked in our hello program, but it does not exist in helloWorld.. O, but in libc So or libc A, so we need to integrate them through links.

gcc -o helloWorld.o helloWorld.c

In the actual project, we can check the link information to determine whether the specified path is correct for those external libraries.

summary

The compilation process is divided into four steps:

  • Will c source program preprocessing is i file
  • The compiler will i file compiled into s assembler
  • The assembler will s assembler compiled into o relocatable target files
  • The linker links the relocatable target file into an executable file

Use the "- v" parameter in the compilation process to view the compilation process in detail, which is very useful in practical development.

One more thing: compilation process in Android NDK

Sample code

jni In the project, the same "Hello World" sample code is added with ndk compilation script Application.mk,Android.mk , enter jni directory and compile with NDK build:

chenls@chenls-PC:jni$ ndk-build
[arm64-v8a] Compile        : helloWorld <= helloWorld.c
[arm64-v8a] Executable     : helloWorld
[arm64-v8a] Install        : helloWorld => libs/arm64-v8a/helloWorld

NDK build script The document mentions that the parameter V=1 starts the build and displays the build command.

In fact, this is similar to - v in gcc. Let's try:

chenls@chenls-PC:jni$ ndk-build V=1
rm -f /home/chenls/Desktop/Android-Native-Development/source/helloWorld/libs/arm64-v8a/*
rm -f /home/chenls/Desktop/Android-Native-Development/source/helloWorld/libs/arm64-v8a/gdbserver
rm -f /home/chenls/Desktop/Android-Native-Development/source/helloWorld/libs/arm64-v8a/gdb.setup
[arm64-v8a] Compile        : helloWorld <= helloWorld.c
rm -f /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o
/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -MMD -MP -MF /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o.d -target aarch64-none-linux-android26 -fdata-sections -ffunction-sections -fstack-protector-strong -funwind-tables -no-canonical-prefixes  --sysroot /home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -Wno-invalid-command-line-argument -Wno-unused-command-line-argument  -D_FORTIFY_SOURCE=2 -fpic -O2 -DNDEBUG  -I/home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni -fstack-protector  -DANDROID  -nostdinc++ -Wformat -Werror=format-security  -c  /home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni/helloWorld.c -o /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o
[arm64-v8a] Executable     : helloWorld
/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -Wl,--gc-sections -Wl,-rpath-link=/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26 -Wl,-rpath-link=/home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o -lgcc -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -latomic -Wl,--exclude-libs,libatomic.a -target aarch64-none-linux-android26 -no-canonical-prefixes    -Wl,--build-id   -nostdlib++ -Wl,--no-undefined -Wl,--fatal-warnings  -lc -lm -o /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/helloWorld
[arm64-v8a] Install        : helloWorld => libs/arm64-v8a/helloWorld
install -p /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/helloWorld /home/chenls/Desktop/Android-Native-Development/source/helloWorld/libs/arm64-v8a/helloWorld
/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-strip --strip-unneeded  /home/chenls/Desktop/Android-Native-Development/source/helloWorld/libs/arm64-v8a/helloWorld

Let's also digest it, which is divided into two steps:

Generated using clang o documentation

Search this message for HelloWorld c. You will see:

/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -MMD -MP -MF /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o.d -target aarch64-none-linux-android26 -fdata-sections -ffunction-sections -fstack-protector-strong -funwind-tables -no-canonical-prefixes  --sysroot /home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -Wno-invalid-command-line-argument -Wno-unused-command-line-argument  -D_FORTIFY_SOURCE=2 -fpic -O2 -DNDEBUG  -I/home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni -fstack-protector  -DANDROID  -nostdinc++ -Wformat -Werror=format-security  -c  /home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni/helloWorld.c -o /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o

As you can see, using clang, HelloWorld C preprocessing, compiling and assembling to generate HelloWorld O documentation.

Using clang + + links

Continue to find HelloWorld o. You will see:

/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -Wl,--gc-sections -Wl,-rpath-link=/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26 -Wl,-rpath-link=/home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o -lgcc -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -latomic -Wl,--exclude-libs,libatomic.a -target aarch64-none-linux-android26 -no-canonical-prefixes    -Wl,--build-id   -nostdlib++ -Wl,--no-undefined -Wl,--fatal-warnings  -lc -lm -o /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/helloWorld

You can see from it that the helloWorld. Net is created using clang + + O link to generate helloWorld.

Use of clang

It can be found that clang is used in ndk compilation, and clang is very similar to gcc. It can also use the parameters mentioned above. Let's take a look at the specific operations.

Tip: if the "- v" parameter is added to the following commands, you can also view the specific calling programs and parameters, which are very similar to gcc.

clang pretreatment

Just put the generated file HelloWorld O changed to HelloWorld i. Then add the - E parameter to get the preprocessed file:

/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -MMD -MP -MF /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o.d -target aarch64-none-linux-android26 -fdata-sections -ffunction-sections -fstack-protector-strong -funwind-tables -no-canonical-prefixes  --sysroot /home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -Wno-invalid-command-line-argument -Wno-unused-command-line-argument  -D_FORTIFY_SOURCE=2 -fpic -O2 -DNDEBUG  -I/home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni -fstack-protector  -DANDROID  -nostdinc++ -Wformat -Werror=format-security  -c  /home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni/helloWorld.c -o /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.i -E

clang compilation

Just put the generated file HelloWorld O changed to HelloWorld s. Then add the - S parameter to get the assembly file:

/home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -MMD -MP -MF /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.o.d -target aarch64-none-linux-android26 -fdata-sections -ffunction-sections -fstack-protector-strong -funwind-tables -no-canonical-prefixes  --sysroot /home/chenls/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot -g -Wno-invalid-command-line-argument -Wno-unused-command-line-argument  -D_FORTIFY_SOURCE=2 -fpic -O2 -DNDEBUG  -I/home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni -fstack-protector  -DANDROID  -nostdinc++ -Wformat -Werror=format-security  -c  /home/chenls/Desktop/Android-Native-Development/source/helloWorld/jni/helloWorld.c -o /home/chenls/Desktop/Android-Native-Development/source/helloWorld/obj/local/arm64-v8a/objs/helloWorld/helloWorld.s -S

Summary of NDK build compilation process

During ndk compilation, clang is called internally. Clang is similar to gcc and can use the same parameters to track the compilation process.

Keywords: C++ Android

Added by catreya on Mon, 17 Jan 2022 22:20:27 +0200