background
Since I came into contact with OpenHarmony in 21 years, I have been particularly interested in the construction system of GN+Ninja, and then I tried to make a simplified version of the Construction System myself. In this competition, if you don't consider using the official IDE and don't want to use makefile (mainly can't write), you still try to use GN+Ninja to complete the construction system of rt1062. Relevant configuration contents are not verified under windows, which can be used in theory.
Project address
https://gitee.com/walker2048/rt1060-gnu-gcc/tree/gn%2Bninja/
The content of this competition will be open source at this address
Description of source directory structure
. ├── build #Compile build profile ├── components #General components (hardware independent components) ├── hardware #Hardware related codes ├── out #Compilation product directory (generated after running the compilation command) ├── solutions #Application directory └── TinyOS #Tencent TinyOS kernel directory
For people who like to toss blindly, there is no happier thing to use their most familiar directory and source code structure (I am in charge of my project, and there are not too many tosses). After all, it takes a lot of time to be familiar with an RTOS. Fortunately, Tencent TinyOS is positioned to lighten the code, simplify the code function and configuration, and can easily adapt. If you don't like this directory structure, you just need to modify the corresponding directory and update the dependency configuration. Also remember to modify build / config / compiler / build Include in GN file_ Dirs field content, update the header file directory. The difficulty is not high.
Advantages of GN + Ninja construction environment
- The code dependency tree is clear
- GN grammar is easy to understand
- Clear division of construction script
- Compilation parameters visible
- Fast construction speed
To sum up, GN + Ninja can be a very high-quality option for individuals or companies when considering new construction systems.
usage method
1. Build configuration command (use export BOARD=TencentOS_tiny_EVB_AIoT command to set the BOARD environment variable first, and then execute it in bash environment):
gn gen out/${BOARD} --args="product = \"${BOARD}\""
Command parsing: if the build script (such as BUILD.gn file) is modified, execute the gn gen command to generate a new ninja build file before ninja knows that the build content has changed. Generally, it is not necessary to split with ninja command. out/${BOARD} is the configuration directory for the specified generated compilation build, and - args = "product =" ${BOARD} "is the parameter passed to GN, telling GN to configure relevant parameters for the environment variable where the product name is ${BOARD} (such as finding the real executable object and related dependencies, as well as compilation parameters).
2. Compile build command:
ninja -C out/${BOARD}
3. Recommended usage:
I'm lazy and like to go directly to ~ / Configure the BOARD environment variable in bashrc and set the command alias:
alias gbuild='gn gen out/${BOARD} --args="product = \"${BOARD}\"" && ninja -C out/${BOARD}' alias gdesc='gn desc out/${BOARD} --args="product = \"${BOARD}\"" //hardware/board/${BOARD}' alias gformat='find . -name *\.gni | xargs gn format && find . -name BUILD.gn | xargs gn format'
For example, the above are gbuild commands, which execute the build configuration command (generally at the level of a few milliseconds to tens of milliseconds) and the compile build command (the new build takes about 11 seconds, and the incremental compilation takes less than 1 second, which is much faster than the official tool); gdesc command is used to obtain the dependency tree and compilation parameters related to compilation configuration; gformat command, used to format gn configuration files.
Maybe a friend will ask how to clean up the compiled products. Just go to the rm -rf out directory.
4. Burn command:
For burning, use pyocd to burn and execute commands (elf file and hex file can be used for burning, both of which have addresses, and there is no need to specify the burning address)
pyocd flash out/${BOARD}/bin/${BOARD}.hex
5. Add source code
To complete the function, it is inevitable to modify the source code, add c source files and h header file. Let's talk about adding c source files first. You can add c source files in the component directory. You only need to add c source files in the component build Modify the contents of the sources field in the GN configuration file. If you need to add new components, you can copy the build of other components GN file, modify the component name, component dependencies (deps), source files and other contents. Add if necessary h header file, which can be divided into two cases. 1. The modified file is only used in the component. At this time, there is no need to define the header file directory (it can be referenced according to the relative path); 2. If the header file is a component external interface definition file, you need to refer to build / config / compiler / build Modify include in GN file_ Dirs field content.
For students who don't want to know the details, just pay attention to the previous content. Those who are interested in understanding the GN construction system can look down.
=====================================================================
Next, let's explain the GN build configuration file and some knowledge points. Because GN is rarely used in domestic projects, Chinese materials are very few. If you want to learn GN knowledge, you can only learn it through gn help command, official website documents (basically similar to help command) and practical application. Fortunately, GN's configuration file is highly readable. You can use it if you understand some basic knowledge points.
Component dependency of GN
GN builds the system. The root node of its dependency tree is an executable object, and then extends to the end component on the dependent component of this object. For example, the dependency tree of this project is expanded as follows (which can be obtained by the command GN desc out / ${BOARD} -- args = "product =" ${BOARD} "" / / hardware / BOARD / ${BOARD} DEPs -- tree. The ${BOARD} environment variable of this command is TencentOS_tiny_EVB_AIoT)
//TinyOS:TinyOS //TinyOS/arch/arm/arm-v7m/common:common //TinyOS/arch/arm/arm-v7m/cortex-m7:cortex-m7 //TinyOS/kernel:kernel //components:components //components/drivers:drivers //components/lists:lists //components/uart:uart //components/utilities:utilities //hardware/board/TencentOS_tiny_EVB_AIoT:startup //hardware/board/TencentOS_tiny_EVB_AIoT/device:device //hardware/board/TencentOS_tiny_EVB_AIoT/xip:xip //solutions/helloworld:helloworld
For example, / / TinyOS:TinyOS in the first line, which is the first dependent component referenced by the executable object. Its path is TinyOS directory under the root directory and build In the GN configuration file, objects with the same name as TinyOS are used. The following example will illustrate the common configuration of GN components.
Syntax description of GN component configuration file
For example, we take the configuration file of TinyOS component as an example (the file path is TinyOS/BUILD.gn)
source_set("TinyOS") { deps = [ "arch/arm/arm-v7m/common", "arch/arm/arm-v7m/cortex-m7", "kernel", ] }
In this file, we define a source code collection object named TinyOS. Why should we name it the same as the folder name? This is one of the rules of GN: if the superior specifies the dependency and only gives the path, the default component object name is the last folder name of the path (implicit call). For example, as shown above, the TinyOS component relies on three components: the common component, the cortex-m7 component, and the kernel component of the arch path. Under these three component folders, there is also build GN configuration file, which defines the component name and content of the component (add deps dependency if there is dependency, and add source code if there is no dependency). deps means the name of the component on which this component depends
Syntax description of end component configuration
The source code contained under the kernel component is defined as follows (the file path is TinyOS/kernel/BUILD.gn). In this document, the component name is consistent with the folder, and it is not necessary to specify the component name when the superior depends on the call. If the component name is inconsistent with the folder name, you need to specify the component name. As in this example, source_set("kernel"), if you want to define another component name (if there are different components in the same directory and the directory name does not match the component name), you can change it to source_set("kernel_name"), when the parent component calls, the component name should be added after the directory, such as "kernel:kernel_name", preceded by the relative directory of the dependent component, followed by the component name (explicit call).
source_set("kernel") { sources = [ "core/tos_barrier.c", "core/tos_binary_heap.c", "core/tos_bitmap.c", "core/tos_char_fifo.c", "core/tos_completion.c", "core/tos_countdownlatch.c", "core/tos_event.c", "core/tos_global.c", "core/tos_mail_queue.c", "core/tos_message_queue.c", "core/tos_mmblk.c", "core/tos_mmheap.c", "core/tos_mutex.c", "core/tos_pend.c", "core/tos_priority_mail_queue.c", "core/tos_priority_message_queue.c", "core/tos_priority_queue.c", "core/tos_ring_queue.c", "core/tos_robin.c", "core/tos_rwlock.c", "core/tos_sched.c", "core/tos_sem.c", "core/tos_stopwatch.c", "core/tos_sys.c", "core/tos_task.c", "core/tos_tick.c", "core/tos_time.c", "core/tos_timer.c", "pm/tos_pm.c", "pm/tos_tickless.c", ] }
As shown above, GN's component dependency is easier to understand, read and maintain than traditional makefile s and cmake files. In terms of component decoupling, if all components can complete the construction of the whole project through healthy dependency (without circular dependency and malignant dependency), functional decoupling is good.
Build script analysis
build/ #Build script directory ├── config #Configuration directory for products │ ├── compiler │ │ └── BUILD.gn #Common configuration contents of compiler, such as compilation optimization settings, etc │ ├── product.gni #Set some compilation judgment parameters related to the product here │ └── rt1062 │ └── BUILD.gn #rt1062 related macro definitions and special compilation parameters └── toolchain ├── BUILD.gn #Tool chain configuration ├── clang.gni #Configuration files reserved for clang └── gcc.gni #Arm none EABI GCC configuration, which is composed of compilation commands .gn #The root configuration read by GN generally only refers to other files BUILD.gn #The configuration here is convenient for adding development boards in the future BUILDCONFIG.gn #Here, the configuration of various tools and development boards are linked together
Basically, you only need to modify the build directory to complete the change of compilation parameters, and the corresponding functions are broken down in detail. It would be better if you could make detailed comments. Because I am not a professional engineer, many comments are inaccurate and even wrong.
The above is the content shared this time. The function of gn will be relatively complex, but it will be very comfortable after using it.