[experience and popular science] practical analysis of compilation problems that may be encountered in C engineering code and their solutions

Posted by Pr0digy on Fri, 31 Dec 2021 23:35:30 +0100

1 Preface

At the beginning of this month, I sorted out the technical articles: The article [gcc compilation optimization series] shows you how C code is compiled , I have received praise from several friends; At the same time, I was particularly surprised to receive the senior leaders of the forum aozima I'm really honored to recommend and reward.



This also confirms from the side that I chose this one [C code compilation] The topic is indeed the confusion encountered by many people, and the article I wrote about compilation problems just reflects its value, so I also want to output the second article on C code compilation as soon as possible, and I sincerely hope that this practical analysis can help more people solve all kinds of compilation problems they encounter.

On the contrary, there have been a lot of things recently. It took three weeks to delay the draft. It's not until now (2022 in another hour).

2 Review

2.1 main contents

I also explained in the previous article. The first article focuses on introducing the whole process of C code compilation in combination with gcc compiler. The second chapter will focus on analyzing what kind of compilation problems should be solved in combination with real code scenarios.

In a word: the first part focuses on the theoretical basis, and this part focuses on practical exercises!

2.2 review of knowledge points

Re emphasize the theoretical basis of the next chapter:

The steps of C code compilation need to go through several key steps such as pre compilation, compilation, assembly and link, and finally generate a binary file, which is the only certificate that can be recognized by the CPU and execute instructions correctly.

I redrawn a diagram, which basically covers the life cycle of a C project code in the development stage. This practical exercise is mainly carried out around this diagram.

It is worth noting that the [compilation problem] mentioned in this paper is mainly in the links of 2 / 3 / 4 / 5 / 6.

3 actual combat analysis

Next, I will point out the matters needing attention or analyze what kind of problems I will encounter and how to solve these problems at each stage in combination with cases.

Note: the code cases intercepted below are from RTT Technology Forum.

3.1 code writing stage

In the code writing stage, there is not much to say, but some people will encounter compilation errors. Why?

Here are some experiences:

  • Install IDE software or development tools, or establish a workspace. Try not to use Chinese. Even if English is poor, it's better to make Pinyin;
  • If you are writing and compiling code under Windows, it is strongly recommended not to make too deep directories. Your workspace path should be as short as possible, which can not guarantee that each compiler can support this long path directory well;
  • Code comments should not be in Chinese as much as possible. There are too many examples of code file confusion caused by Chinese coding problems; If you must use Chinese, you must agree on the coding format. GBK or UTF-8. Here, UTF-8 is recommended. About their differences and connections, Recommended reading.
  • The code writing style should follow the specifications as much as possible. Your development team can do whatever it requires. There is no difference between good and bad. With specifications, you need to abide by them.

Take a look at the posts in several forums that encounter compilation problems in the code writing stage:

Compilation problems caused by Windows command line restrictions : in essence, the path mentioned above should not be too long and the directory should not be too deep; Under Windows, you can write the contents of the command line into a text file first and transfer it. To avoid this problem, many SDK compilation processes are played like this under Windows, which is more troublesome.

Chinese coding problem : the essence is to write less Chinese notes, even if it's a little poor English. Isn't there a translation software? Just make sure the grammar is OK.

Problems related to Chinese coding , but also:

Code specification problem : we have agreed, let's abide by it together!

3.2 precompiling phase

For the things to be done in the precompile stage, refer to my last article. Here we focus on several compilation problems that are very easy to encounter in the precompile stage.

In order to better show the compilation errors, I will use English supplemented by Chinese to describe the compilation errors below.

3.2.1 No such file or directory

Here are some typical examples:

Example 1 : the root cause of the problem is that the header file is not included, and may also include the nested inclusion of header files. For example, header file A contains header file B. If header file B is not found, include header file A can be solved;

Example 2 : the problem still lies in include. This header file does exist, but the compiler reports that it cannot be found. The reason is that the directory where the header file is located is not in the list of header files retrieved by the compiler. This retrieval list generally includes system level include directories (such as / usr/include, / usr/local/include under linux), The include directory where the compiler is located, and finally the user-defined directory. There are different ways to specify this directory. Taking gcc compilation as an example, you need to add * * - Ixxx * * in CFLAGS (I is in uppercase, and xxx can be a relative path or an absolute path). For details, please refer to the following This article . In addition, if you have header files with the same name in your project, you must pay attention to the order in which they are searched. This is the only reference to determine which header file your code include s.

Example 3 : the essence of this problem is still the problem of header file search.

Example 4 : this essence is also the problem of finding Lu Jin in the header file. The landlord solved the problem by copying the header file to the specified Lu Jin, but I think it is better to add the path of the original header file into the path of header file retrieval.

To sum up, when No such file or directory appears, focus on the following aspects:

  • First confirm whether the prompted file really does not exist? If the file exists, check it down;
  • If the file is a header file, you should first consider whether the directory where the header file is located is in the list retrieved by the compiler header file?
  • If the file is a C file, you need to check the addition of Makefile or CMake or sconc configuration to the C file.

3.2.2 macro definition problems

In C code, it can be said that macro definitions are really too common and ubiquitous.

It can be said impolitely that no great God who claims to be proficient in C language can not 6 play with macro definitions.

In the macro definition, the compilation problem often encountered is how to expand the macro definition?

What is the impact on context code compilation after macro definition expansion?

It is not difficult to solve the compilation problem caused by macro definition.

To know how to view the code prototype after macro definition expansion, you can try to skip to chapter 4.2.2 to learn in advance.

In addition, there is another kind of macro definition error. The more common is that a macro definition is defined in the a.h header file, but the C file referencing the header file does not include the header file, resulting in compilation error; This error is essentially a header file inclusion problem mentioned in 3.2.1.

The following is about the compilation error of macro definition, intercepting the typical errors in the Forum:

Example 1 : compilation failed due to incorrect macro definition.

Example 2 : the essence is still the problem of compiler macro definition. The header file contains a series of problems.

Example 3 : the judgment that the GCC macro definition is missing in the header file leads to some header files or macro definitions not defined, and then an error is reported during compilation.

In addition, when retrieving the macro definition in the forum, I found such a problem** problem **, it's a little interesting. I'll leave it to you for discussion.

3.2.3 problems of conditional compilation

Common conditional compilation methods include:

  • #If is usually followed by a macro definition expression. When the value of the expression is non-0, #if the following code will participate in the compilation, otherwise it will not participate;
  • #else is similar to * * #if * *;
  • #elif is a nested writing method of conditional compilation, which supports multiple conditional compilation;
  • #idef is usually followed by a macro definition. When this macro definition is defined (it may be that #define is explicitly used in the header file, or it may be passed in through the compilation option. For example, gcc supports - Dxxx to define macro definitions), the following code will participate in the compilation, otherwise it will not participate;
  • #if defined(xxx) this is #ifdef's other way of writing, which is essentially equivalent;
  • #endif indicates the end of conditional compilation code.

Here are some additional points:

  • When a macro definition xxx is not defined, its default value is 0, so the result of using * * #if xxx * * is false;
  • #ifdef and * * #if defined(xxx) are only used for macro definition, whether it is defined or not, regardless of the value of the macro definition; Use #if * * if you want to focus not only on whether there is a definition, but also on the value of the definition;
  • When * * #if is used, the following expressions can use logical operators such as & &, | * * and so on.

Under the preprocessing of conditional compilation, we often see that many tailorable and portable codes are implemented by these means.

Take an example of RT thread kernel component code:

/* From RT thread / components / fish / fish H fragment */

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2010-03-22     Bernard      first version
 */
#ifndef __FINSH_H__
#define __FINSH_H__

#include <rtthread.h>

#if defined(_MSC_VER)
    #pragma section("FSymTab$f",read)
#endif

typedef long (*syscall_func)(void);
#ifdef FINSH_USING_SYMTAB
#ifdef __TI_COMPILER_VERSION__
    #define __TI_FINSH_EXPORT_FUNCTION(f)  PRAGMA(DATA_SECTION(f,"FSymTab"))
#endif
#ifdef FINSH_USING_DESCRIPTION
#ifdef _MSC_VER
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \
                const char __fsym_##cmd##_name[] = #cmd;            \
                const char __fsym_##cmd##_desc[] = #desc;           \
                __declspec(allocate("FSymTab$f"))                   \
                const struct finsh_syscall __fsym_##cmd =           \
                {                           \
                    __fsym_##cmd##_name,    \
                    __fsym_##cmd##_desc,    \
                    (syscall_func)&name     \
                };
#pragma comment(linker, "/merge:FSymTab=mytext")

#elif defined(__TI_COMPILER_VERSION__)
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \
                __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd);           \
                const char __fsym_##cmd##_name[] = #cmd;            \
                const char __fsym_##cmd##_desc[] = #desc;           \
                const struct finsh_syscall __fsym_##cmd =           \
                {                           \
                    __fsym_##cmd##_name,    \
                    __fsym_##cmd##_desc,    \
                    (syscall_func)&name     \
                };

#else
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)                      \
                const char __fsym_##cmd##_name[] RT_SECTION(".rodata.name") = #cmd;    \
                const char __fsym_##cmd##_desc[] RT_SECTION(".rodata.name") = #desc;   \
                RT_USED const struct finsh_syscall __fsym_##cmd RT_SECTION("FSymTab")= \
                {                           \
                    __fsym_##cmd##_name,    \
                    __fsym_##cmd##_desc,    \
                    (syscall_func)&name     \
                };

#endif
#else
#ifdef _MSC_VER
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \
                const char __fsym_##cmd##_name[] = #cmd;            \
                __declspec(allocate("FSymTab$f"))                   \
                const struct finsh_syscall __fsym_##cmd =           \
                {                           \
                    __fsym_##cmd##_name,    \
                    (syscall_func)&name     \
                };
#pragma comment(linker, "/merge:FSymTab=mytext")

#elif defined(__TI_COMPILER_VERSION__)
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \
                __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd);           \
                const char __fsym_##cmd##_name[] = #cmd;            \
                const struct finsh_syscall __fsym_##cmd =           \
                {                           \
                    __fsym_##cmd##_name,    \
                    (syscall_func)&name     \
                };

#else
#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc)                      \
                const char __fsym_##cmd##_name[] = #cmd;                            \
                RT_USED const struct finsh_syscall __fsym_##cmd RT_SECTION("FSymTab")= \
                {                                                                   \
                    __fsym_##cmd##_name,                                            \
                    (syscall_func)&name                                             \
                };

#endif
#endif /* end of FINSH_USING_DESCRIPTION */
#endif /* end of FINSH_USING_SYMTAB */

If it is the first time to contact the conditionally compiled code, or even an old hand, when reading the nested code of N-tier conditionally compiled code for the first time, he will be discouraged every minute.

Therefore, the conditional compilation problem mentioned in this section will not only be encountered when compiling the code, but also when you read the code first.

Unfortunately, if your code is displayed in the place surrounded by conditional compilation, you should find out which code block of your code should be compiled at the first time, because most of the time, it is often because your macro definition switch is not configured correctly, which leads to the compilation of code that should not be compiled. Naturally, the compilation report is wrong.

Therefore, in the face of code compiled under this condition, the first time is to understand and confirm whether the code expanded by the compiler preprocessing is the code you want?

How to confirm?

You can try to skip to chapter 4.2.2 to learn in advance.

Due to the space problem, only one forum about conditional compilation is intercepted here problem , for your reference.

3.3 compilation phase

The compilation stage may also be a disaster area for novices.

Why?

Because this involves the basic syntax of C language. If you don't understand and understand the basic syntax carefully enough, you may make some compilation errors.

Here are some typical examples:

Example 1 : the reason for this compilation error is that the structure prototype has been upgraded and the name has been changed, and then some member variables in the new version have disappeared, resulting in a syntax error.

Example 2 : the core of this problem is that it does not contain the corresponding header file, which makes the structure type unrecognizable, and then reports a syntax error.

Example 3 : the essence of this problem is a syntax error caused by the disappearance of the member variables of the structure due to the improper macro switch.

3.4 compilation stage

In the assembly phase, there are fewer compilation errors. Why?

This is because most of the time we write high-level C language, and a few write assembly code. If there is an error at the stage from C code to assembly code, it is likely that the parameters passed to compilation are not correct.

Typically, under ARM processor, its ARM instruction set is different from Thumb instruction set; If you write mixed programming in C language and assembly (many underlying codes have this writing requirement), you must find out whether you write ARM instruction or Thumb instruction, and the corresponding compilation options passed to the compiler are different.

Here are some typical examples:

Example 1 : this should be a question about assembly instructions, which is answered in the question post.

Example 2 : the direct compilation and conversion of different compilers involves assembly instructions. You can go to the comment box to see your answers.

Example 3 : see the comment box for specific compiler support for assembly code.

3.5 link phase

The link stage is a key step in completing the compilation. Whether all the C code you write can be completely concatenated into an executable program depends on this step. Therefore, this step is often the hardest hit area of compilation and error reporting.

Here are several common compile link errors:

3.5.1 undefined reference to 'xxx'

This error is really too common. Many people say that it is "compile error". In fact, the accurate term should be "link error".

The core of its error is that the xxx function (symbol) cannot find the implementation of xxx in all your C codes (which have been compiled into. o files) and all library files (including static libraries and dynamic libraries, of course, including standard C libraries) that you join to participate in the link.

After understanding this, you should know how to solve the compilation problem of link error.

Give me a few examples from the forum problem Look, it's really the hardest hit area.

To solve such problems, I generally take the following steps:

  • Confirm whether the xxx symbol is a function, macro definition or variable;
  • If it is a macro definition, it should be that your macro definition is not included, resulting in the macro definition not being expanded;
  • If it is a variable or function, confirm whether the code is involved in the compilation. For details, see i file or o documentation;
  • In another case, if it is a library function (standard library or third-party library), confirm which library the function is in and whether the library file is in your link list. For example, gcc compilation uses - lxxx to specify the linked library.

3.5.2 cannot find -lxxx

This means that xxx is a library file and cannot be found when linking. Generally, the following aspects can be considered to solve this kind of problem:

  • First, confirm whether there is any mistake in the xxx library file? Under gcc compilation, a libxxx A's static library or lixxxx So, where the library name is xxx instead of libxxx A or libxxx So, novices are often easy to ignore;
  • Make sure that the way to retrieve the library is correct. For example, for some third-party libraries, you need to use - Lxxx to pass in the path of your library under gcc to find your library;
  • Check whether there is recursive dependency of library functions and the link order of library functions, which are often prone to errors.

3.5.3 multiple definition of 'xxx'

This error is the same as the error prompt. The key to troubleshooting is to find the duplicate definition.

Take several typical examples:

Example 1 : the function is repeatedly defined incorrectly. There is an answer in the comment box.

Example 2 : two c files have a clear function, and the links are all linked together. Can you not define them repeatedly? static function.

Example 3 : the main function is defined repeatedly. This is rare. See the comment box.

3.6 conversion phase

Generally, there are few problems in this conversion stage. When compiling with GCC, the objcopy command used in this step is:

Generate bin file:

objcopy -O binary xxx.elf xxx.bin

Survival hex file:

objcopy -O ihex xxx.elf xxx.hex

The * * - R * * option is often added in actual engineering projects:

objcopy -O binary -R .eh_frame -R .init -R .fini -R .comment xxx.elf xxx.bin
objcopy -O ihex -R .eh_frame -R .init -R .fini -R .comment  xxx.elf xxx.hex

The * * - R * * option means to remove these paragraphs.

$ objcopy -h
Usage: objcopy [option(s)] in-file [out-file]
 Copies a binary file, possibly transforming it in the process
 The options are:
  -R --remove-section <name>       Remove section <name> from the output
     --remove-relocations <name>   Remove relocations from section <name>

3.7 other stages

Download and run phase - > function test phase - > BUG removal phase - > version release phase

This paper does not elaborate on these stages too much. After all, each chip platform has different download methods and debugging and operation methods, and the test methods of each function are also very different. Everyone has different methods to debug and solve bugs. They do their own things for their own use.

At the stage of version release, the functions are basically stable, the planned functional requirements have been met, and the software release process has begun. This is also the stage that every project is most expected to reach. What needs special attention here is (the lesson of blood and tears): the software release must have a standardized process, and the released code must be tracked to the specified submission record. Otherwise, if something goes wrong, you may want to cry without tears, and you may be affected by various DISS.

4 share a few experiences

4.1 share some very wonderful compilation problems

4.1.1 macro definition

Example 1: a freeRTOS macro definition problem. I wrote an article before( [freeRTOS Development Notes] write down freeRTOS-v9 Upgrade 0.0 to freeRTOS-v10.0 four point four ), you can have a look if you are interested.

4.1.2 what are static and inline doing

Example 2: static and inline modify function definitions. You can refer to this example Posts , I have written an article on this issue before( [gcc compilation optimization series] differences and relations between static and inline ), you can have a look if you are interested.

4.1.3 determination of environmental variables

Example 3: Incredible problems caused by environment variables? Look at this problem ! Please be careful when using environment variables!

4.1.4 examples

Example 4: finally, I reported a friend I met in my actual work. I checked it for a while and found the clue.

The error reported is: multiple definition of 'xxx'!

At that time, I checked one by one according to the points listed above, and found that they were not those.

Strange! Can you play with flowers? Finally, the method in Chapter 4.2.2 is to output the complete log of the link. It's silly!

There are repeated * * o file is added to the link, which does not duplicate the definition * * no wonder!

The following is a simple copy of the scene at that time. If you have something, change it, and if not, encourage it!

Our entire compilation and construction is based on Makefile, which is divided into N modules. Each sub module has its own makefile,
All codes that need to be compiled under this module will be listed in Makefile,
Under normal circumstances, it is written like this:

SRC_C-y := ./src/a.c
SRC_C-y += ./src/b.c
SRC_C-y += ./src/c.c
SRC_C-y += ./src/d.c

In this way, you can finally participate in the link O file: a.o, B.O, C.O, D.O. there is no problem in compiling;
The man in the back didn't know how to touch it by mistake or what. He changed the colon to a plus sign:

SRC_C-y += ./src/a.c
SRC_C-y += ./src/b.c
SRC_C-y += ./src/c.c
SRC_C-y += ./src/d.c

The result is the last to participate in the link O file is: a.o b.o c.o d.o... a.o b.o c.o d.o
This is the of this module o if you copy all the documents, you will certainly report duplicate definitions!

After further follow-up, it is found that there are some defects in the construction process. The Makefile of each sub module will be loaded twice,
This leads to SRC if written in the second way_ C-y will become:/ src/a.c ./src/b.c ./src/c.c ./src/d.c ./src/a.c ./src/b.c ./src/c.c ./src/d.c
However, if you use the first method, you won't. You need to understand the grammatical differences between = and + = in Makefile. I wrote an article before article , those interested can understand.

In short, at that time, I felt that this problem was really a little dog blood, and we should take it as a warning.

4.2 share several common methods for troubleshooting compilation problems

4.2.1 open the complete log output of the compilation process

Why did you do that?

In this way, you can see the specific details passed to the compiler by your compilation build environment, so as to learn more about the behavior of the compiler.

4.2.1.1 Makefile build environment

Generally, when compiling and building, in order to keep the compiled log output clean, the complete compiled output will be turned off by default. You can see something like this:

    CC    components/mqtt/src/impl/MQTTConnectClient.o
    CC    components/mqtt/src/impl/MQTTDeserializePublish.o
    CC    components/mqtt/src/impl/MQTTPacket.o
    CC    components/mqtt/src/impl/MQTTSerializePublish.o
    CC    components/mqtt/src/impl/MQTTSubscribeClient.o
    CC    components/mqtt/src/impl/MQTTUnsubscribeClient.o
    CC    components/mqtt/src/impl/iotx_mqtt_client.o
    CC    components/mqtt/src/mqtt_api.o

You can't even see what kind of compiler CC is. It may be gcc, ARMCC or others.

So how to open the complete output of the compiled log? You can try the following command to add a control variable when you enter make:

make V=1 or make VERBOSE=1

In this way, the compilation output you see is very complete. Specifically, you can see which compiler you used and which parameters you passed in. It's just that there are many and long logs. It's time to test your ability to retrieve log information.

"arm-none-eabi-gcc" -c -MD  -DMCU_FAMILY=\"mcu_xxx\"  -DSYSINFO_PRODUCT_MODEL=\"XXX_xxx\" -DSYSINFO_DEVICE_NAME=\"xxx\"   -DuECC_PLATFORM=uECC_arch_other -mcpu=arm968e-s -march=armv5te -mthumb -mthumb-interwork -mlittle-endian -w -save-temps=obj -DCFG_OS_FREERTOS=1 -DWIFI_BLE_COEXIST -DBK_DEBUG_UART=BK_UART_1 -DBK_CLI_UART=BK_UART_1 -DBK_CLI_ENABLE=0 -DUSR_CLI_MAX_COMMANDS=96 -DBLE_5_0                 -DEN_LONG_MTU -DEN_COMBO_NET -DEN_AUTH     -ggdb -Os  -Wall -Wfatal-errors -fsigned-char -ffunction-sections -fdata-sections -fno-common -std=gnu11  -DPLATFORM=\"xxx\"  -include /xxx/application/bbb/xxxos_config.h  -Wall -Werror -Wno-unused-variable -Wno-unused-parameter -Wno-implicit-function-declaration -Wno-type-limits -Wno-sign-compare -Wno-pointer-sign -Wno-uninitialized -Wno-return-type -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-value -Wno-strict-aliasing -Wall -Werror -Wno-unused-variable -Wno-unused-parameter -Wno-implicit-function-declaration -Wno-type-limits -Wno-sign-compare -Wno-pointer-sign -Wno-uninitialized -Wno-return-type -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-value -Wno-strict-aliasing -Wall -Werror -Wno-unused-variable -Wno-unused-parameter -Wno-implicit-function-declaration -Wno-type-limits -Wno-sign-compare -Wno-pointer-sign -Wno-uninitialized -Wno-return-type -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-value -Wno-strict-aliasing -I/xxx/platform/mcu/xxx/bk_sdk/config -I/xxx/platform/mcu/xxx/bk_sdk/release -I/xxx/platform/mcu/xxx/bk_sdk/xxx/func/ble_wifi_exchange -I/xxx//components/wireless/bluetooth/ble/host/profile -I/xxx//include/wireless/bluetooth/blemesh -I/xxx//include/network/coap -I/xxx//include/network/hal -I/xxx//include/network/http -I/xxx//include/network/lwm2m -I/xxx//include/network/umesh -I/xxx//include/network/athost -I/xxx//include/network/sal -I/xxx//include/network/netmgr -I/xxx//include/network/rtp -I/xxx//include/utility/yloop -DBUILD_BIN -DCLI_CONFIG_SUPPORT_BOARD_CMD=1 -DCONFIG_xxxos_CLI_BOARD -DCONFIG_xxxos_UOTA_BREAKPOINT -DCONFIG_xxxos_CLI_STACK_SIZE=4096 -DDISABLE_SECURE_STORAGE=1 -DCFG_I2C1_ENABLE=1 -Dxxxos_LOOP -DINFRA_COMPAT -DINFRA_MD5 -DINFRA_NET -DINFRA_SHA256 -DINFRA_TIMER -DINFRA_STRING -Dxxxos_COMP_CLI -Dxxxos_COMP_KV -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" -DCONFIG_HTTP_SECURE=1 -DCOAP_SERV_MULTITHREAD -Dxxxos_COMP_VFS -D__FILENAME__='"mem.c"'  -o /xxx/out/bbb/bbb@xxx/modules/platform/mcu/xxx/bk_sdk/xxx/func/lwip_intf/lwip-2.0.2/src/core/mem.o /xxx/platform/mcu/xxx/bk_sdk/xxx/func/lwip_intf/lwip-2.0.2/src/core/mem.c 

The output log is gcc, so you need to understand the compilation parameters of gcc. For example, - Dxxx represents macro definition, - Ixxx represents header file search directory, etc.

Note: make plus V=1 or VERBOSE=1 is generally well written. Makefile will do so, but it does not mean that everyone who writes makefile will do so.

4.2.1.2 CMake construction environment

Method 1:

Similar to Makefile, CMake also has a switch with complete output. After inputting make, add a control variable:

make VERBOSE=1

The effect without VERBOSE=1 is:

[ 16%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_import.c.o[ 16%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_init.c.o[ 17%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_init_copy.c.o[ 17%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_init_multi.c.o[ 17%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_init_set.c.o[ 17%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_init_set_int.c.o[ 18%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_init_size.c.o[ 18%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_invmod.c.o[ 18%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_invmod_slow.c.o[ 18%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_is_square.c.o[ 19%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_jacobi.c.o[ 19%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_karatsuba_mul.c.o[ 19%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_karatsuba_sqr.c.o[ 20%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_kronecker.c.o[ 20%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_lcm.c.o[ 20%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_lshd.c.o[ 20%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_mod.c.o[ 21%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_mod_2d.c.o[ 21%] Building C object src/CMakeFiles/yyy.dir/xxx/bn_mp_mod_d.c.o

Add the effect of VERBOSE=1:

[  3%] Building C object src/CMakeFiles/yyy.dir/yyy/bncore.c.ocd /yyy/build/x86_release/src && /usr/bin/gcc -DENCRYPTO_MODE=AES -DHAL_SHIELD=0 -I/sysroot/usr/include -I/yyy/inc -I/yyy/inc/hal -I/yyy/src/hal/9x07/linux -I/yyy/inc/hal/log -I/yyy/inc/hal/crypto -I/yyy/inc/hal/crypto/tommath -I/yyy/inc/hal/crypto/skb -I/yyy/inc/hal/asn1 -I/yyy/inc/uicc_framework -I/yyy/inc/uicc_framework/apdu -I/yyy/inc/uicc_framework/channel -I/yyy/inc/uicc_framework/comm -I/yyy/src/uicc_framework/comm -I/yyy/inc/uicc_framework/dispatcher -I/yyy/inc/uicc_framework/profile -I/yyy/inc/uicc_framework/filesystem -I/yyy/inc/uicc_framework/nvm -I/yyy/inc/uicc_framework/utils -I/yyy/inc/uicc_framework/ppi -I/yyy/inc/uicc_framework/tf -I/yyy/inc/applet -I/yyy/inc/applet/common -I/yyy/inc/applet/common/util -I/yyy/inc/applet/common/uicc -I/yyy/inc/applet/ecasd -I/yyy/inc/applet/isdp -I/yyy/inc/applet/usim -I/yyy/inc/applet/isdr -I/yyy/inc/applet/nusim  -Wall -pthread -fPIC -Wno-missing-braces -s -m32 -Werror -Wno-unused-function -Wno-unused-variable -Wno-unused-value -O2 -Os -Wmissing-prototypes -Wstrict-prototypes -DDEBUG=0 -I/yyy/build/x86_release   -o CMakeFiles/yyy.dir/yyy/bncore.c.o   -c /yyy/src/yyy/bncore.c

In fact, the final essence of CMake is Makefile.

Method 2:

At cmakelists Txt configuration file, add the following settings to achieve the above effect.

set ( CMAKE_VERBOSE_MAKEFILE on )

Note: with this configuration, you only need to enter make, but its disadvantage is that you have to change cmakelists when you don't want complete output Txt configuration file is not so convenient to use. So I personally recommend method 1.

4.2.1.3 scons build environment

This construction method is also supported by RTT. We can see how its compiled complete output is:

scons --verbose

Without control items, the output is as follows:

$ sconsscons: Reading SConscript files ...scons: done reading SConscript files.scons: Building targets ...scons: building associated VariantDir targets: buildCC build/kernel/components/dfs/src/dfs.oCC build/kernel/components/dfs/src/dfs_file.oCC build/kernel/components/dfs/src/dfs_fs.oCC build/kernel/components/dfs/src/dfs_posix.oCC build/kernel/components/drivers/i2c/i2c-bit-ops.oCC build/kernel/components/drivers/i2c/i2c_core.oCC build/kernel/components/drivers/i2c/i2c_dev.oCC build/kernel/components/drivers/misc/pin.oCC build/kernel/components/drivers/mtd/mtd_nand.oCC build/kernel/components/drivers/mtd/mtd_nor.oCC build/kernel/components/drivers/rtc/rtc.oCC build/kernel/components/drivers/rtc/soft_rtc.oCC build/kernel/components/drivers/sdio/block_dev.oCC build/kernel/components/drivers/sdio/mmc.oCC build/kernel/components/drivers/sdio/mmcsd_core.oCC build/kernel/components/drivers/sdio/sd.oCC build/kernel/components/drivers/sdio/sdio.oCC build/kernel/components/drivers/serial/serial.oCC build/kernel/components/drivers/spi/sfud/src/sfud.oCC build/kernel/components/drivers/spi/sfud/src/sfud_sfdp.oCC build/kernel/components/drivers/spi/spi_core.o

Output after adding verbose control:

arm-none-eabi-gcc -o build/kernel/components/finsh/msh_file.o -c -march=armv7-a -marm -msoft-float -Wall -g -gdwarf-2 -O0 -DHAVE_CCONFIG_H -D__RTTHREAD__ -DRT_USING_NEWLIB -I. -Idrivers -Iapplications -I/yyyrt-thread/include -I/yyyrt-thread/libcpu/arm/common -I/yyyrt-thread/libcpu/arm/cortex-a -I/yyyrt-thread/components/cplusplus -I/yyyrt-thread/components/drivers/include -I/yyyrt-thread/components/drivers/spi -I/yyyrt-thread/components/drivers/spi/sfud/inc -I/yyyrt-thread/components/net/sal_socket/include -I/yyyrt-thread/components/net/sal_socket/include/socket -I/yyyrt-thread/components/net/sal_socket/impl -I/yyyrt-thread/components/net/sal_socket/include/dfs_net -I/yyyrt-thread/components/net/sal_socket/include/socket/sys_socket -I/yyyrt-thread/components/net/netdev/include -I/yyyrt-thread/components/net/lwip-2.1.2/src -I/yyyrt-thread/components/net/lwip-2.1.2/src/include -I/yyyrt-thread/components/net/lwip-2.1.2/src/arch/include -I/yyyrt-thread/components/net/lwip-2.1.2/src/include/netif -I/yyyrt-thread/components/libc/compilers/common -I/yyyrt-thread/components/libc/compilers/gcc/newlib -I/yyyrt-thread/components/libc/posix/src -I/yyyrt-thread/components/libc/posix/pthreads -I/yyyrt-thread/components/libc/posix/signal -I/yyyrt-thread/components/libc/posix/termios -I/yyyrt-thread/components/libc/posix/aio -I/yyyrt-thread/components/libc/posix/getline -I/yyyrt-thread/components/lwp -I/yyyrt-thread/components/dfs/include -I/yyyrt-thread/components/dfs/filesystems/devfs -I/yyyrt-thread/components/dfs/filesystems/elmfat -I/yyyrt-thread/components/dfs/filesystems/ramfs -I/yyyrt-thread/components/dfs/filesystems/romfs -I/yyyrt-thread/components/finsh -I/yyyrt-thread/examples/utest/testcases/kernel /yyyrt-thread/components/finsh/msh_file.c

As for the meaning of the specific compiled output log, it depends on the specific compiler. gcc is commonly used by us. We should be familiar with it.

4.2.2 open the output of intermediate files in the compilation process

4.2.2.1 gcc compilation environment

This option I Last article Also mentioned, here is a summary and a brief introduction. It's good to use it to troubleshoot compilation problems and assembly code level performance problems.

This parameter is - save temps = obj. Let's practice:

gcc/gcc_helloworld$ ./build.sh clean   Clean build done !gcc/gcc_helloworld$ gcc/gcc_helloworld$ lsbuild.sh  main.c  README.md  sub.c  sub.hgcc/gcc_helloworld$ gcc/gcc_helloworld$ ./build.sh allinonegcc -c main.c -o main.o -save-temps=objgcc -c sub.c -o sub.o -save-temps=objgcc main.o sub.o -o testgcc/gcc_helloworld$ gcc/gcc_helloworld$ lsbuild.sh  main.c  main.i  main.o  main.s  README.md  sub.c  sub.h  sub.i  sub.o  sub.s  test

That's it i documents S files, and * * o files * * are output at the same time.

If there is only one main in the project C source file, you can also do it in one step.

gcc main.c -o test -save-temps=obj

These * * i file * * s files, and * * o file * *, we call it intermediate temporary file.

Summary:

  • To view the preprocessed code file, see * * i * * file (you are not afraid of complex conditional compilation. In this file, all prototypes are exposed)
  • To view the corresponding assembly code generated by C code, see * * s * * file
  • To view the symbol table information corresponding to C code, see * * o * * documents

4.2.2.2 KEIL construction environment

In fact, KEIL also has corresponding settings. I don't have a ready-made IDE environment. I found it online An article , the presentation was pretty good. You can refer to it.

4.3 friendly reminder

Life is limited, effective coding.

Please respect every line of code you write.

Please ensure that your code compilation is always: 0 warning, 0 error, 0 bug.

5 New Year greetings

I wish you all the best in the new year, fly high, 2022, set sail by dream!

6 more sharing

Welcome to my github warehouse 01workstation , daily share some development notes and project practice, welcome to correct the problem.

You are also welcome to follow my CSDN home page and column:

[CSDN homepage: Architect Li Ken]

[RT thread homepage: Architect Li Ken]

[C/C + + language programming column]

[GCC column]

[information security column]

[RT thread Development Notes]

[freeRTOS Development Notes]

If you have any questions, you can discuss with me and answer them. Thank you.

Topics: C Makefile rt-thread gcc