Code engineering automatic compiling construction method without appointing source code file paths one by one
By unifying the directory structure and automating path searching, the cumbersome problem of manually specifying file paths and dependencies in existing technologies is solved, enabling intelligent building of code projects and multi-project collaboration, thus improving compilation efficiency and project management efficiency.
Patent Information
- Application Number
- CN202511688544.6
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- Filing Date
- 2025-11-18
- Publication Date
- 2026-01-23
AI Technical Summary
Existing compilation and build methods require manually specifying the path and dependencies of each file, resulting in cumbersome configuration, difficult maintenance, and difficulty in adapting to the needs of large software projects and multi-project collaborative development.
It adopts a unified directory structure and automated path search, automatically searches and manages source file and header file paths through makefiles, generates dependency files, and supports collaborative compilation and building of multiple projects.
It achieves fully automated compilation and building of code projects, improving compilation efficiency and accuracy, simplifying configuration, supporting collaborative management of multiple projects, and possessing good adaptability and scalability.
Smart Images

Figure CN121387301A_ABST
Abstract
Description
TECHNICAL FIELD
[0001] The present application relates to the technical field of software engineering, and particularly relates to a code engineering automatic compilation and construction method without specifying source code file paths one by one. BACKGROUND
[0002] In the software development process, the compilation and construction of code engineering is an indispensable key link. Compilation refers to compiling code source files to generate object files, and construction refers to constructing all object files and dependent library files to generate the final executable binary file. This process is of great significance in various software development, especially in large software projects, embedded system development and other scenarios. The efficiency of compilation and construction directly affects the quality and progress of software development.
[0003] Currently, the compilation and construction of code engineering mainly adopts two ways: one is to use an integrated development environment, and the other is to write a makefile file. Integrated development environments such as KEIL, VITIS, DEVC++, visual studio, STM32CubeIDE, etc. provide a graphical compilation setting interface, while the makefile method defines the compilation rules through a script language. Both methods face some common technical problems in practical application: 1) manually adding the search paths of code header files one by one, in the IDE, all header file search paths need to be specified one by one through the compilation setting item in the toolbar, while for makefile, the storage folder of each header file is often specified one by one through the -I parameter; 2) manually adding the search paths of all source code files to be compiled one by one, in the IDE, there is usually a default specified folder path to store source files, which requires all source files to be directly placed in the same default specified folder, otherwise all search paths of all source code files to be compiled need to be manually added in the compilation setting bar; for makefile, all source files to be compiled need to be specified one by one through the -c parameter; 3) each source file needs to be specified separately when compiling the header file path, and cannot be automatically dependent, since each source code file may include different code header files, so if the dependent header file is not in the same directory as the source file, the header file search path needs to be specified through the -I parameter in the makefile when compiling each source file into an object file (.o suffix), of course, all header file storage paths can also be directly specified in a large range through the -I parameter when compiling each source file, but this will increase the header file search time during code engineering compilation and thus reduce the compilation efficiency; 4) the object files participating in the construction need to be manually added one by one when constructing the code; 5) the full paths of the object files and intermediate files to be deleted need to be manually added one by one when deconstructing the code.
[0004] In large software projects, code files are usually organized by functional modules and distributed in different directory levels. Each module may contain multiple source files and header files, which are often stored in different paths. Existing compilation and build methods require developers to manually specify the compilation path of each source file, the search path of each header file, and the generation path of each object file. When the project size is large, the workload of manual configuration is considerable and prone to errors.
[0005] Especially during the iterative development process of a project, code files may be frequently added or deleted, and directory structures may be adjusted. Whenever such changes occur, developers need to modify the compilation configuration accordingly. In an integrated development environment, this usually means modifying the file paths in the compilation settings one by one; in a makefile approach, the file path list needs to be manually updated. This process is not only tedious and time-consuming, but also prone to omissions, leading to compilation failures.
[0006] Another prominent problem is dependency management. Each source file may include different header files during compilation, which may in turn include other header files, forming a complex dependency network. Traditional compilation and build methods have difficulty automatically tracking these dependencies, and when a header file is modified, developers need to manually determine which source files need to be recompiled or use a conservative strategy to recompile all source files, the former is prone to errors, and the latter is inefficient.
[0007] In addition, in the scenario of collaborative development of multiple related projects, each sub-project may need to be compiled independently while being managed uniformly. Existing compilation and build methods lack effective multi-project collaboration mechanisms, often requiring separate compilation commands for each project or complex scripts for coordination, which increases management complexity.
[0008] Therefore, there is an urgent need for a compilation and build method that can automatically handle file paths, intelligently manage dependencies, and support multi-project collaboration to address the problems of existing technology, such as complicated configuration, difficult maintenance, and low efficiency. SUMMARY
[0009] The present application overcomes the problem of manual specification of each file path and tedious maintenance of dependencies in traditional compilation and build, and achieves intelligent construction of code projects through unified directory structure and automated path search, significantly improving the automation level of software construction and engineering management efficiency, with good adaptability and scalability.
[0010] To achieve the above purpose, the present application adopts the following scheme: A code project automatic compilation and build method without specifying source code file paths one by one, comprising the following steps: S1: create a makefile file under the code engineering path, create a shell variable DIR_PROJECT in the makefile file to save the relative path of the code engineering storage location relative to the storage location of the makefile file, create a shell variable CC to save the absolute path of the compiler for compiling the code engineering, and create a shell variable APP to save the generation path of the finally generated executable binary file; S2: create a same-named folder src and inc under each level directory of the code engineering, respectively, wherein the src folder is used to store all code source files under the level directory, and the inc folder is used to store all code header files under the level directory; S3: perform the following configuration operations by adding shell statements in the makefile file: S301: search all src folders under the code engineering path DIR_PROJECT to obtain the folder paths of all code source files and save them to the shell variable src_dirs; S302: search all inc folders under the code engineering path DIR_PROJECT to obtain the folder paths of all code header files and save them to the shell variable inc_dirs; S303: retrieve the code source file suffixes under all folder paths saved by the shell variable src_dirs to obtain the full paths of all code source files and save them to the shell variable srcs; S304: uniformly replace the suffixes of all full paths of code source files in the shell variable srcs with.o to obtain the generation paths of all object files corresponding to the source files and save them to the shell variable objs; S4: add a compilation rule in the makefile file, use the compiler specified by the shell variable CC to compile each code source file in the shell variable srcs to generate the corresponding object file, add the compilation parameter -I to specify the shell variable inc_dirs as the header file search path during compilation, and add the compilation parameter -Wp, -MD to automatically generate a dependency relationship file; S5: add a linking rule in the makefile file, when building the source code engineering, use the compiler specified by the shell variable CC to link all object files in the shell variable objs with the required library files to generate an executable binary file; S6: Add a deconstruction rule in the makefile file, when deconstructing the source code project, delete all object files, dependency files and executable binary files generated in the compilation process by executing the make clean command.
[0011] As preferred, in step S3, the shell statements used in path searching and file list generation are as follows: The statement used in step S301: src_dirs:= $(shell find $(DIR_PROJECT) -type d -name src); The statement used in step S302: inc_dirs := $(shell find $(DIR_PROJECT) -type d -name inc); The statement used in step S303: srcs := $(foreach dir, $(src_dirs), $(wildcard $(dir) / *.c)); The statement used in step S304: objs := $(patsubst %.c, %.o, $(srcs)).
[0012] As preferred, in step S4, the compilation rule in the makefile file is as follows: %.o : %.c $(CC) -Wp,-MD,$(dir $@).$(notdir $@).d -c -o $@ $<$(foreach dir, $(inc_dirs), -I$(dir)) Wherein, the path of the dependency file is automatically generated by combining $(dir $@) and $(notdir $@).d.
[0013] As preferred, in step S5, the linking rule in the makefile file is as follows: ${APP}:$(objs) $(CC) $^ -o $@.
[0014] As preferred, in step S5, when linking, link the posix pthread library and the multi-threaded C runtime library by adding the linking parameter-pthread, and / or link the real-time library by adding the linking parameter-lrt.
[0015] As preferred, in step S6,.PHONY: clean declaration is added in the makefile file to declare clean label as a pseudo-target to avoid the conflict caused by the existence of a file named clean in the directory where the makefile is located.
[0016] As preferred, in step S4, the generated dependency files are also stored in a separate directory from the object files by modifying the generation path of the dependency file, which specifically includes the following steps: A prefix parameter is added in the compilation rule to point the generation path of the dependency file to a specific dependency file subdirectory under the object file output directory, and a shell variable DEP_DIR is created in the makefile file to save the path of the dependency file subdirectory; the path of the dependency file subdirectory is obtained by suffix replacement based on the generation path of the object file, and the dependency relationship files corresponding to each source file are stored in the same dependency file directory.
[0017] As preferred, step S4 further includes the following dependency integration steps: The automatically generated dependency relationship file is introduced by adding an include instruction in the makefile file, and the include instruction uses the wildcard function to match all dependency relationship files with.d suffix under the object file output directory; a minus prefix is added before the include instruction to make the make tool ignore the dependency relationship files that have not been generated when compiling for the first time; The include instruction is wrapped with a conditional judgment statement, and the include operation is only performed when the dependency relationship file exists, and the conditional judgment statement is obtained by combining ifneq and wildcard functions.
[0018] The application also provides a compilation and construction method for multiple code projects, which includes the following steps: The code project automatic compilation and construction method provided in any of the above solutions does not need to specify the path of each source code file, and the makefile file for compiling and constructing a sub-code project is created and configured in each sub-code project directory of the multiple code projects; A top-level makefile is created in the parent directory of all sub-code projects, and the compilation and construction process of each sub-project is called in sequence by the shell statement make -C<sub-code project path> in the top-level makefile, and all sub-projects are compiled and constructed synchronously by executing a single make command in the top-level directory.
[0019] As preferred, the code project is divided into a hardware abstraction layer and an application layer, and the following method is used for hierarchical compilation and construction of the code: The hardware abstraction layer code file and the application layer code file are respectively stored in a hardware abstraction layer code subdirectory and an application layer code subdirectory of a code project; A first makefile is created in the hardware abstraction layer code subdirectory, and is used to compile the hardware abstraction layer code file into a hardware library file; A second makefile is created in the application layer code subdirectory, and is used to compile and link the hardware library file and the application layer code file together into an executable application program; A top-level makefile is created under a general directory of the code project, and the hardware abstraction layer and the application layer code are automatically compiled and built in an integrated manner through nested calling of the first makefile and the second makefile.
[0020] The present application at least has the following beneficial effects: (1) the full-process automation of code project compilation and building is realized, the tedious operation of manually specifying each file path is avoided through unified directory structure and automatic path search, and the configuration workload is significantly reduced; (2) the dependency relationship between source files and header files is intelligently tracked through automatic dependency relationship management, and the recompilation of related source files is automatically triggered when the header file is modified, so that the compilation accuracy is ensured and the compilation efficiency is improved; (3) the multi-project collaborative compilation and building is supported, the compilation process of each sub-project is uniformly coordinated through the top-level makefile, the unified management of complex software systems is realized, and the building process of multi-module projects is greatly simplified; (4) a perfect project de-building mechanism is provided, all compilation generated files can be quickly cleaned up, the engineering directory is kept neat, and the conflict problem in the cleaning process is avoided through pseudo-target declaration; (5) good platform adaptability and scalability are provided, different development environments and project scale requirements are supported through relative path design and modular architecture, and the project is convenient for transplantation and extension. BRIEF DESCRIPTION OF DRAWINGS
[0021] Figure 1 A code project automatic compilation and building method principle flowchart is provided for the present application; Figure 2 A code implementation example diagram of the code project automatic compilation and building method is provided for the present application; Figure 3 A compilation effect example diagram of the code project automatic compilation and building method is provided for the present application; Figure 4 A compilation process example diagram of the code project automatic compilation and building method is provided for the present application. DETAILED DESCRIPTION
[0022] The present application will be further described in detail below with reference to the drawings, so that those skilled in the art can implement the present application according to the description.
[0023] As Figures 1-4 shown, the code engineering automatic compilation construction method provided by the present application does not need to specify the source code file path one by one, which includes the following steps: S1: Create a makefile file under the code engineering path, create a shell variable DIR_PROJECT in the makefile file to save the relative path of the code engineering storage location relative to the storage location of the makefile file, create a shell variable CC to save the absolute path of the compiler for compiling the code engineering, and create a shell variable APP to save the generation path of the finally generated executable binary file.
[0024] In the initial step of the code engineering automatic compilation construction method, a makefile file needs to be created under the root directory or a specified subdirectory of the code engineering. Makefile is a script file used for automatic compilation and construction process, which guides the compilation tool how to generate target files by defining a series of rules and variables. In this step, three key shell variables are created in the makefile file: DIR_PROJECT, CC and APP. Variable DIR_PROJECT is used to save the relative path of the code engineering storage location relative to the storage location of the makefile file, for example, if the makefile is located in the root directory of the project, DIR_PROJECT can be set to the current directory (i.e. “.”), if the makefile is located in a subdirectory, it may need to be set to “..” or a more complex relative path. The design of such relative path makes the whole project portable, even if the project is moved to other locations, as long as the relative path relationship does not change, there is no need to modify the makefile, and it is very convenient to modify. Variable CC is used to save the absolute path of the compiler for compiling the code engineering, for example, the path of GCC compiler can be “ / usr / bin / gcc”, which ensures that the specified compiler version is used in the compilation process, avoiding compilation errors caused by changes in system environment variables. Variable APP is used to save the generation path of the finally generated executable binary file, for example, it can be set to a path like “. / bin / app” to specify the location of the output file. The definition of these variables is based on shell script syntax, implemented through assignment operation, they serve as the configuration basis of the whole compilation process, ensuring that the subsequent steps can dynamically reference the engineering path, compiler selection and output target.
[0025] The DIR_PROJECT variable reduces the dependence of the project on the absolute path through the relative path mechanism, thereby enhancing flexibility; the CC variable guarantees the determinacy of the compiler by specifying the absolute path, thereby avoiding version conflicts; and the APP variable unifies the management of output targets, thereby facilitating the subsequent calling of the linking step. These variables are defined in the makefile through simple assignment statements, such as "DIR_PROJECT :=." or "CC := / usr / bin / gcc", and are referenced multiple times in the entire makefile, forming a centralized configuration design. In actual operation, the user can flexibly adjust the values of these variables according to the project structure, for example, for an embedded project, the CC variable can point to the path of the cross-compiler, and the APP variable can point to the executable file output directory of the embedded device. This design makes the method applicable to various programming environments and platforms without the need to rewrite the core rules.
[0026] S2: Create a folder named src and an inc folder under each level directory of the code project, respectively, wherein the src folder is used to store all code source files under the level directory, and the inc folder is used to store all code header files under the level directory.
[0027] Under each level directory of code engineering, create folders with the same name, src and inc. The src folder is used to store all code source files under this level directory, such as files with.c,.cpp, etc. suffix; the inc folder is used to store all code header files under this level directory, such as files with.h suffix. This way of creating folders with the same name at each level makes the code structure highly standardized and modularized. For example, in a multi-level project, the root directory, sub-module directory, and even deeper directory will contain src and inc folders, thus naturally separating source files and header files by function or module. This approach is based on the modular design principle in software engineering, simplifying file retrieval and management through uniform folder naming. This structure allows compilation tools to quickly locate all source files and header files through simple pattern matching without manually specifying the path of each file. For example, in a large project, the traditional method may require adding hundreds of file paths one by one, while this method automatically covers all relevant files through folder naming conventions. In use, users only need to follow this folder structure when creating projects, placing source files in the corresponding src folder and header files in the corresponding inc folder. In actual implementation, if the original project files are scattered in different directories, users can first reorganize the files, which will greatly simplify subsequent maintenance. This structure also supports incremental development of code. When adding new modules, you only need to create src and inc folders in the corresponding directory and place the files in them without modifying the makefile. In addition, this design promotes code readability and maintainability, as developers can intuitively understand module boundaries and file ownership.
[0028] S3: Perform the following configuration operations by adding shell statements in the makefile file: S301: Search all src folders under the code engineering path DIR_PROJECT to get the folder paths of all code source files and save them to the shell variable src_dirs; S302: Search all inc folders under the code engineering path DIR_PROJECT to get the folder paths of all code header files and save them to the shell variable inc_dirs; S303: Retrieve the code source file suffixes under all folder paths saved in the shell variable src_dirs to get the full paths of all code source files and save them to the shell variable srcs; S304: Replace the suffixes of all code source file full paths in the shell variable srcs with.o uniformly to get the generation paths of all source file corresponding object files and save them to the shell variable objs.
[0029] A series of shell statements are added in the makefile file to perform path search and file list generation, which is the key to automatic compilation. The S3 step includes four sub-steps: S301 searches all src folder paths and saves them to the src_dirs variable; S302 searches all inc folder paths and saves them to the inc_dirs variable; S303 retrieves the full path of all source files and saves them to the srcs variable; S304 generates the object file path by suffix replacement and saves it to the objs variable. These operations are based on the combination of shell commands and makefile functions, for example, S301 uses the "find" command to recursively search all directories named "src" under the DIR_PROJECT path, and the result is stored in the src_dirs variable. Similarly, S302 uses the same method to search for "inc" directories. S303 then uses the "foreach" and "wildcard" functions to iterate through each directory in src_dirs, match all source file suffixes (such as.c files), and generate a full path list. S304 uses the "patsubst" function to replace the source file path suffix in srcs with.o to get the object file path.
[0030] These shell statements take advantage of the file system retrieval capabilities of the operating system and the pattern processing functions of makefile to achieve dynamic file discovery. For example, the find command is based on directory tree traversal and can cover all subdirectories to ensure that no src or inc folder is missed; the wildcard function quickly collects files through wildcard matching. This automation avoids the tediousness and errors of manually maintaining file lists. In terms of usage, these statements are automatically run when the makefile is executed, generating variables for subsequent steps. In actual operation, if files are added or deleted in the project, these variables will be automatically updated without user intervention. For example, when a new src folder is added, the find command will automatically include it in the next compilation. This design significantly improves the adaptability and stability of the compilation system, especially in agile development environments that change frequently.
[0031] S4: Add a compilation rule in the makefile file, use the compiler specified by the shell variable CC to compile each code source file in the shell variable srcs, generate the corresponding object file, add the compilation parameter -I to specify the shell variable inc_dirs as the header file search path during compilation, and add the compilation parameter -Wp, -MD to automatically generate dependency relationship files.
[0032] In the makefile file, add a compilation rule to compile each source file in srcs using the compiler specified by the variable CC to generate the corresponding object file. During compilation, add the compilation parameter -I to specify all paths in the inc_dirs variable as the header file search path, which means that the compiler will search for header files referenced by the #include directive in these paths. At the same time, add the compilation parameter -Wp, -MD to automatically generate dependency files, which record the list of header files that each source file depends on during compilation. For example, for the source file "main.c", the compilation may generate the "main.o" object file and the "main.d" dependency file, the latter contains all the header file paths referenced by "main.c". The -I parameter specifies multiple header file search paths to ensure that the compiler can correctly parse all dependencies, and the -Wp, -MD parameter triggers the compiler's dependency generation function, which is based on the pre-processing stage of header file expansion to generate accurate dependencies. This automatic dependency management avoids the shortcomings of manually maintaining dependency lists in traditional methods. In terms of usage, the compilation rule is usually defined in the form of a pattern rule, such as "%.o : %.c", where variables and parameters are used to dynamically construct the compilation command. In actual operation, when the user executes the make command, the compiler will process each source file in srcs one by one to generate object files and corresponding.d files. If the header file changes, the make tool will automatically recompile the affected object files based on the dependencies in the.d file, ensuring the accuracy of the build. This mechanism greatly reduces the compilation errors caused by header file modifications and improves the build efficiency.
[0033] S5: In the makefile file, add a linking rule to link all object files in the shell variable objs with the required library files using the compiler specified by the shell variable CC to generate an executable binary file when building the source code project.
[0034] Add a link rule in the makefile file. When building the source code project, use the compiler specified by the variable CC to link all object files in the objs variable with the required library files to generate the final executable binary file. The link rule is usually defined as a command, where the objs variable provides the paths of all object files, and the compiler combines these files with external libraries (such as system libraries or third-party libraries) to generate the target executable file, whose path is specified by the APP variable. For example, the link command is like "$(CC) $(objs) -o $(APP) -lm", where "-lm" indicates linking the math library. The linker combines multiple object files into a single executable file by resolving symbol references in the object files, while resolving external dependencies. This method automates object file list management, ensuring that all compiled object files are correctly included in the linking process. The link rule can be flexibly extended, such as adding parameters like "-pthread" to link the thread library or "-lrt" to link the real-time library, to adapt to different engineering needs. In actual operation, the linking step is automatically triggered after compilation is complete, and users only need to execute a make command to complete the entire build. This design simplifies the build process, especially for complex projects with a large number of object files, where manual management is prone to errors.
[0035] S6: Add a deconstruction rule in the makefile file. When deconstructing the source code project, execute the make clean command to delete all object files, dependency files, and executable binary files generated during the compilation process.
[0036] Add a deconstruction rule in the makefile file. When deconstructing the source code project, execute the "make clean" command to delete all object files, dependency files, and executable binary files generated during the compilation process. The deconstruction rule is usually defined as one or more shell commands, using the "rm" command to delete specified files. For example, the rule can include "rm -f $(objs)" to delete all object files, and "rm -f $(APP)" to delete the executable file. Deconstruction cleans up intermediate files and output files to restore the project to its original state, facilitating re-construction or release. In terms of usage, the deconstruction rule is usually combined with the ".PHONY" declaration to mark "clean" as a pseudo-target, avoiding conflicts with files of the same name. In actual operation, after the user executes "make clean", all generated files are removed, ensuring that the next build starts from scratch and avoiding interference from old files. This mechanism is particularly suitable for continuous integration environments, where frequent clean builds are required to ensure consistency.
[0037] To further demonstrate the feasibility of the specific implementation mode of the method, in Figure 2 a specific makefile file writing example under code engineering is provided.
[0038] Figure 3 For the compilation use effect example of the code engineering automatic compilation construction method without specifying the source code file path one by one, the compilation process and effect of the makefile written by the method of the application are explained in combination with the figure: Figure 3 The effect of using the makefile to compile the project C_Project to generate the final executable target file lxgy_OLTGND_APP after inputting the make instruction in the shell terminal is shown. It can be seen that when all the.o files are compiled, the corresponding.o.d hidden file will be automatically generated, which automatically records the full path of all header files on which the.o file depends, and is automatically read and depended by the compilation process. As Figure 3 shown,.lg_time.o.d records the full path of all header files on which the compilation of lg_time.o depends, which avoids the need to specify the full path of all header files on which each.o file to be compiled depends in the makefile in the traditional makefile writing method, greatly improves the makefile writing efficiency, and is beneficial to software engineering management, avoiding the disadvantage of having to modify the makefile again after the header file included by the source file is added, deleted or modified.
[0039] Figure 4 For the compilation process example of the code engineering automatic compilation construction method without specifying the source code file path one by one written by the method provided by the application, the process effect of inputting make to compile and generate the target executable file lxgy_OLTGND_APP and inputting make clean to clear the compilation in the shell instruction terminal of ubuntu16.04 is shown.
[0040] It should be noted that part of the code, including specific parameter names, is shown by a test project, not the actual code in a specific project, but the processing logic uses the method provided by the application, and those skilled in the art should be able to understand the example significance and make appropriate modifications and configurations according to the actual project requirements. The code example of the method provided by the application can obtain the running effect as Figure 3 shown, and the compilation process is shown in Figure 4 , and the description provided in Figures 2-4The example shown is a set of corresponding process demonstrations of makefile file code implementation, project compilation effect and compilation process of test code engineering. When this method is applied to actual project engineering, parameter configuration can be performed according to actual needs, which is obvious.
[0041] Through the organic combination of the above steps, a highly automated code engineering compilation construction method is realized. First, the method greatly simplifies the compilation configuration process, and users do not need to manually specify the paths of source files and header files one by one, reducing manual intervention and configuration errors. Second, through automatic dependency management, the accuracy and efficiency of the construction are significantly improved. When the code structure changes, the system can adaptively adjust without modifying the script. Third, the entire method has high flexibility and portability, and is suitable for multiple programming languages and engineering scales, from simple applications to complex embedded systems. Finally, the deconstruction function ensures the neatness of engineering management, facilitating maintenance and iteration. Overall, the method has significant advantages in improving development efficiency and reducing maintenance costs, while enhancing the scalability and stability of the code engineering.
[0042] In another technical solution, as shown in Figure 2 The shell statement used in step S3 for path retrieval and file list generation is as follows: The statement used in step S301 is: src_dirs := $(shell find $(DIR_PROJECT) -type d -name src); The statement used in step S302 is: inc_dirs := $(shell find $(DIR_PROJECT) -type d -name inc); The statement used in step S303 is: srcs := $(foreach dir, $(src_dirs), $(wildcard $(dir) / *.c)); The statement used in step S304 is: objs := $(patsubst %.c, %.o, $(srcs))。
[0043] As shown in Figure 2Lines 5 and 10 of the code shown, steps S301 and S302, utilize the `find` command to recursively search the code project directory. The `-type d` parameter limits the search to directory types, and the `-name` parameter specifies the directory name to search. The `find` command starts from the root directory specified by the `DIR_PROJECT` variable, traverses all subdirectories, and collects the target directory paths that meet the criteria into the corresponding shell variables. This search mechanism is based on the tree structure of the file system, using depth-first or breadth-first traversal algorithms to ensure that no directory level is missed. For example, in a complex project with multiple levels of subdirectories, the `find` command can automatically search for all directories named "src" and "inc", regardless of whether they are at the top level of the project or nested in multiple levels of subdirectories. The search depth of the `find` command can be adjusted according to project needs, for example, by limiting the search range using the `-maxdepth` parameter, with options including 3 levels, 5 levels, or unlimited depth, depending on the complexity of the project structure. This design allows the project to flexibly adapt to different directory structures, effectively supporting both flat, simple projects and deeply nested large projects.
[0044] like Figure 2 Line 6 of the code shown, step S303, includes a shell statement consisting of a foreach loop function and a wildcard pattern matching function. The foreach function iterates through each directory path in the src_dirs variable, temporarily assigning it to the dir variable. For each directory path, the wildcard function matches all files ending in .c and returns a full list of their paths. This combination achieves two levels of expansion: first, directory-level expansion retrieves all source file directories, and then file-level expansion collects specific source files. The wildcard function uses wildcards for filename pattern matching, where *.c can be replaced with other source file extensions, such as *.cpp, *.cc, etc., providing flexibility for supporting multiple programming languages. In practice, if a project contains multiple types of source files, this can be achieved through a combination of multiple wildcard statements, such as matching both .c and .cpp files simultaneously. This design ensures the completeness and accuracy of source file collection; even if a project contains thousands of source files distributed across different directories, this statement can automatically generate a complete list of file paths, greatly simplifying project configuration.
[0045] like Figure 2The key to the shell statement in line 7, step S304 of the code shown is the `patsubst` pattern replacement function. It replaces all `.c` suffixes in source file paths with `.o` suffixes according to a specified pattern, thus generating the corresponding object file paths. The `patsubst` function uses pattern matching, where `%.c` matches all strings ending with `.c`, and `%.o` defines the target pattern after replacement. This suffix replacement, based on string pattern conversion, ensures the correspondence between source files and object files. For example, the path `project / src / main.c` becomes `project / src / main.o` after replacement, maintaining the same directory structure and filename foundation. In actual operation, this one-to-one path mapping relationship allows the compilation system to accurately know the location of the object file generated after compiling each source file, providing necessary information for subsequent compilation and linking steps. It is worth noting that the object file suffix is not limited to `.o` and may differ on different platforms, such as `.obj`. Simply adjust the replacement pattern accordingly to adapt to different environments. This design maintains the platform adaptability and scalability of the compilation system while ensuring the accuracy and consistency of file mapping.
[0046] By specifying shell statements for path searching and file handling, a reliable foundation for file discovery and path processing is provided for the entire automated build process. These statements significantly improve the automation of project file management, eliminating the need for manual file list maintenance; enhance the build system's adaptability to changes in project structure, eliminating the need to modify the build script when the directory structure is adjusted or files are added or deleted; provide flexible scalability, supporting multiple file types and project sizes; and greatly reduce the probability of configuration errors, improving the reliability of the build process. Overall, these technical features work together to make code project build management more intelligent and efficient.
[0047] In another technical solution, such as Figure 2 As shown in lines 24 and 25 of the code, in step S4, the compilation rules in the makefile are specifically the following pattern rules: %.o : %.c $(CC) -Wp,-MD,$(dir $@).$(notdir $@).d -c -o $@ $<$(foreach dir, $(inc_dirs), -I$(dir)) The paths to dependency files are automatically generated by combining $(dir $@) and $(notdir $@).d.
[0048] The compilation pattern rule is defined as %.o : %.c followed by the compilation command. This pattern rule is a key build rule in the Makefile, where %.o : %.c represents the general rule: any .o file depends on a .c file with the same name. The % symbol is a wildcard, matching any common base filename. In the compilation command, $(CC) represents the compiler path variable, the -c parameter indicates that the source files are compiled but not linked, -o $@ specifies that the output file name is the object file (i.e., %.o in the rule), and $< represents the first dependent file (i.e., %.c in the rule). This pattern rule utilizes the implicit rule mechanism of the make tool to establish a dependency relationship for each pair of source and object files. When the make tool executes, it determines whether recompilation is needed based on the file timestamps: if the .c file is newer than the corresponding .o file, or the .o file does not exist, the compilation command is triggered. In actual operation, for each .c file in the project, the make tool automatically instantiates this rule and generates the specific compilation command. For example, for the main.c file, make will create the dependency relationship main.o : main.c and execute the corresponding compilation command. This pattern rule design greatly simplifies the writing of compilation rules, eliminating the need to specify rules for each source file individually, and significantly improving the simplicity and maintainability of the makefile.
[0049] The compilation parameters `-Wp,-MD,$(dir $@).$(notdir $@).d` enable the automatic generation of dependency files. `-Wp` and `-MD` are compiler preprocessing options instructing the generation of dependency information; `$(dir $@)` extracts the directory paths of object files; `$(notdir $@)` extracts the base filenames of object files; and the final `.d` suffix indicates a dependency file. This mechanism leverages the dependency generation capabilities of GCC and other compatible compilers. When the compiler processes the `-Wp,-MD` parameters, it analyzes all `#include` directives in the source files during the preprocessing stage, generating complete dependency information and writing it to the specified `.d` file. For example, compiling `src / main.c` to generate `build / main.o` will simultaneously generate the `build / main.d` dependency file, which records the paths of all header files that `main.c` depends on. The storage location of dependency files can be flexibly configured: they can be stored in the same directory as the object files or centrally in a dedicated dependency file directory. This automatic dependency tracking ensures that when the contents of a header file change, all source files that depend on that header file will be recompiled, guaranteeing the accuracy and completeness of the build process.
[0050] The `$(foreach dir, $(inc_dirs), -I$(dir))` part of the compiler command dynamically generates compiler parameters for all header file search paths. The `foreach` function iterates through each header file directory path in the `inc_dirs` variable, generating a `-I` compiler parameter for each path, forming a complete list of header file search paths. The `-I` parameter tells the compiler to search for header files in the specified directories. When header files are included using the `#include` directive in source files, the compiler searches according to these paths in order. This dynamic generation mechanism ensures that all `inc` directories found through automated searching are included in the header file search path, regardless of their location within the project. In actual execution, the generated parameters are in the form of `-I. / inc -I. / submodule / inc -I. / third_party / inc`, providing the compiler with a complete header file search space. This design solves the problem of manually maintaining header file paths in traditional compilation methods, especially when the project is large and has many modules. At the same time, this dynamic path specification method ensures project portability; when sharing code between different environments or developers, there is no need to adjust the header file path configuration.
[0051] Through specific pattern rules and compilation parameter configurations, the system achieves comprehensive automated management of the source file compilation process, greatly simplifying the configuration of compilation rules and covering the compilation requirements of all source files with a single pattern rule. It enables precise dependency tracking, ensuring correct recompilation is triggered when header files are modified; provides comprehensive header file search support, avoiding compilation failures due to missing header file paths; and enhances the intelligence and adaptability of the build system, automatically responding to changes in project structure. Overall, these technical features collectively construct a stable and efficient compilation environment, significantly improving the build quality and development efficiency of code projects.
[0052] In another technical solution, such as Figure 2 Figure 2 In lines 14 and 15 of the code shown, in step S5, the linking rules in the makefile are specifically the following pattern rules: ${APP}:$(objs) $(CC) $^ -o $@.
[0053] The linking rule defines the specific ${APP}:$(objs) and the linking command that follows. This rule defines the generation of the final executable file, where ${APP} represents the executable file target path defined by the APP variable, and $(objs) represents the collection of all object files that need to be linked. This target-dependent relationship declaration establishes a dependency chain between the executable file and all object files, ensuring that all necessary object files have been successfully compiled before the linking operation is performed. This linking rule utilizes the task scheduling mechanism of the make tool. When the make tool detects that the executable file represented by APP does not exist or its timestamp is earlier than any object file, it will automatically trigger the execution of the linking command. In actual operation, the linking rule serves as the last stage of the entire build process and is started after the source files have been compiled into object files. For example, in a medium-sized project containing dozens of source files, the make tool will first compile each.c file in parallel or serially to generate the corresponding.o file, and then execute the linking command to combine all object files into the final executable program after all compilation tasks are completed. This phased task management ensures the orderliness and correctness of the build process, avoiding linking errors caused by incomplete compilation of partial files.
[0054] The linking command $(CC) $^ -o $@ contains multiple key technical features: $(CC) calls the pre-defined compiler path variable, which can usually be gcc, g++, clang, etc. The specific choice depends on engineering requirements; $^ is a make tool automatic variable that represents the complete list of all dependent files in the rule, which in this case is all object file paths in the objs variable; $@ is also an automatic variable that represents the target file in the rule, which is the executable file path defined by the APP variable; and the -o parameter explicitly specifies the output file name. The use of automatic variables allows the linking command to dynamically adapt to different project sizes and environment configurations. Whether the objs variable contains ten or one thousand object files, $^ can automatically expand to a complete file list, ensuring that the linker can obtain all necessary input files. The linking command will automatically expand according to the project configuration, such as automatically linking the C++ standard library when using a C++ compiler, and adding debugging information parameters when debugging mode is enabled. This design greatly improves the generality and reusability of the linking rule, and the same set of rules can be applied to projects of different sizes and configurations without the need to write linking instructions for each project individually.
[0055] Although the basic link command form is simple, it can be extended in many ways in practical applications. For example, you can add custom parameters before the link command, such as optimization level options -O1, -O2 or -O3, which can significantly affect the performance and size of the final program; You can also add debugging information parameters -g to facilitate subsequent debugging analysis; You can also add warning control parameters -Wall, -Wextra, etc. to increase the strictness of code quality checks. As the last link in the build process, the linker is responsible for combining multiple object files and various library files into a single executable image, while resolving all external symbol references. In actual operation, the linker will link according to the specified object file order, handle global symbol relocation and resolution. For complex engineering projects, you can also add library search path parameters -L to the link command to specify the search location of custom library files; Add library linking parameters -l to specify the specific library files that need to be linked. For example, -lm links the math library, -lrt links the real-time library, etc. This flexible extension mechanism ensures that the linking rules can adapt to various special build requirements, whether it is a simple single-file program or a complex large system can provide appropriate support.
[0056] By defining clear and concise linking rules, the entire executable file generation process is fully automated, greatly simplifying the configuration work in the linking phase, avoiding the tedious process of manually enumerating object files through the automatic variable mechanism; Provide highly flexible extension support to adapt to different complexity of engineering linking requirements; Ensure the correct dependency relationship between each stage of the build process to prevent linking errors caused by missing files or inconsistent versions; Significantly improve the reliability of the build system, making the generation of the final executable file predictable and repeatable. Overall, these technical features together build an efficient linking environment.
[0057] In another technical solution, in step S5, when linking, link the posix pthread thread library and the multi-threaded C runtime library by adding the link parameter -pthread, and / or link the real-time library by adding the link parameter -lrt.
[0058] -pthread is a comprehensive compiler and linker parameter that enables multiple important functions during the linking phase: first, it ensures that the linker can find and link the concrete implementation of the POSIX threads library; second, it configures the C runtime library to use a thread-safe version; finally, it also defines necessary preprocessor macros that affect how the code is compiled. The -pthread parameter provides multithreading support to programs through a standardized interface, unlike directly linking a specific thread library, which maintains better cross-platform compatibility. During actual operation, when the linker processes the -pthread parameter, it automatically selects the appropriate thread library implementation based on the current target platform, which may link libpthread.so on Linux systems or different thread library implementations on other Unix-like systems. This abstraction layer design allows the same code to be correctly compiled and run on multiple platforms without adjusting the build configuration for each platform. For developers, adding this one parameter during linking provides complete multithreading development environment support, including thread creation, synchronization primitives, thread-local storage, and other key functions.
[0059] The real-time library (librt) provides various time-related system function extensions, including high-precision clock access, POSIX shared memory, asynchronous I / O, and other advanced features. The -lrt parameter instructs the linker to search for a library file named librt in the system library path and link the functions in it into the final executable file. The real-time library, as an extension of system core functions, provides applications with time processing and inter-process communication capabilities beyond the standard C library. For example, using the clock_gettime() function can achieve nanosecond-level time precision, much higher than the second-level precision provided by the standard time() function; using POSIX semaphores can achieve efficient inter-process synchronization; using shared memory can achieve zero-copy inter-process transmission of large-capacity data. The linker will search for librt.so (dynamic library) or librt.a (static library) in the library search path based on the parameter and combine the function implementations in it with the program code. For applications that require precise time control or high-performance inter-process communication, such as real-time data processing systems, high-frequency trading platforms, or multimedia processing software, linking the real-time library is almost a necessary choice.
[0060] The -pthread and -lrt parameters can be selectively used according to the actual engineering needs, either one of them can be used alone, or both of them can be used in combination, and the system can be configured according to the specific functional requirements of the application program. For example, a program that only uses basic thread functions without high-precision timers can only add the -pthread parameter; a program that requires precise time control but does not require multi-threading can only add the -lrt parameter; and a complex application program that requires both multi-threading and high-precision timing functions can use both parameters at the same time. The linker will process the linking of each library in the order specified by the parameters to resolve symbol dependencies. In addition to these two core parameters, other linking parameters such as -lm to link the math library and -ldl to link the dynamic loading library can be added according to the needs in actual application to form a complete library dependency solution.
[0061] In step S6, the.PHONY: clean declaration is added to the makefile file to declare the clean label as a pseudo-target to avoid conflicts caused by the existence of a file named clean in the directory where the makefile is located.
[0062] The.PHONY: clean declaration in it is a key instruction used in makefile to identify pseudo-targets. Pseudo-targets are special makefile targets that do not correspond to actual file generation. They are usually used to execute a series of operation instructions rather than create files. The clean target is a typical pseudo-target, which is used to clean up the intermediate files and output files generated during the compilation process, and does not generate any output file named "clean". The make tool defaults to considering each target as corresponding to an actual file, and if a file with the same name as the target exists in the current directory, it will cause the dependency relationship to be judged incorrectly. For example, if a "clean" ordinary file is accidentally created in the project directory, when the user executes the make clean command, the make tool will detect that the "clean" file already exists and seems to be the latest, and thus incorrectly think that the cleaning operation does not need to be performed. Such conflicts are not uncommon in actual development environments, especially in team collaboration projects, different developers may inadvertently create various named files. The pseudo-target declaration explicitly tells the make tool that the target does not correspond to an actual file, which fundamentally avoids the occurrence of such misjudgment problems.
[0063] The.PHONY declaration is a built-in directive for the make tool, with the syntax format of.PHONY: followed by one or more target names. When the make tool parses the makefile, it will specially process the targets declared as.PHONY, skipping the file existence and timestamp checks for these targets and directly executing their corresponding command sequences. This mechanism ensures that the pseudo-target commands are executed every time they are called, regardless of the existence of the same-named file. The.PHONY declaration changes the way the make tool recognizes target properties. For ordinary targets, make checks the timestamp relationship between the target file and the dependent files, and only executes the command when the dependent files are newer. For pseudo-targets, make completely ignores the file system state and unconditionally executes the related commands. In actual use, the.PHONY declaration is usually placed in a prominent position in the makefile, such as the beginning of the file or near the corresponding target definition, to improve code readability. In addition to the clean target, other common pseudo-targets include install, uninstall, dist, and other management tasks. A makefile can contain multiple.PHONY declarations, each of which can specify multiple pseudo-targets. This flexibility makes project management more standardized and systematic.
[0064] By introducing the.PHONY declaration mechanism, the build system provides reliable management target support, eliminates the target execution conflicts caused by the same-named files, and ensures the reliable execution of management commands. It provides a clear way to distinguish between file generation targets and management operation targets, enhancing the readability and maintainability of makefiles. It lays the foundation for complex build process management, supporting multi-task coordination and automated execution.
[0065] In another technical solution, in step S4, the generated dependency relationship file is also stored in a separate directory from the object file by modifying the generation path of the dependency relationship file, specifically including the following steps: A prefix parameter is added to the compilation rule to point the generation path of the dependency relationship file to a specific dependency file subdirectory under the object file output directory, and a shell variable DEP_DIR is created in the makefile file to save the path of this dependency file subdirectory. The path of the dependency file subdirectory is obtained by suffix replacement based on the generation path of the object file, and the dependency relationship files corresponding to each source file are stored in the same dependency file directory.
[0066] In large software projects, the number of dependency files generated during the compilation process is often very large. If these.d files are mixed with.o object files in the same directory, it will cause the directory content to be chaotic, and bring great difficulty to file management and cleaning operations. The design of centralized storage of dependency files is to solve this practical problem. This separate storage scheme is based on the design principle of separation of concerns, and different types of build products are classified and stored. Object files usually need to participate in the final linking process, while dependency files are only used in the build phase to determine the recompilation range, and the use scenarios and life cycles of the two are different. By creating an independent dependency file storage directory, we can achieve clearer build product management. In actual implementation, we can choose to create a specific dependency file subdirectory under the object file output directory, such as deps / ,.dependencies / , etc. The specific directory naming can be determined flexibly according to project specifications and team habits.
[0067] The DEP_DIR variable can be constructed in many ways, the most common being based on the object file output path through string replacement. For example, if the object file output directory is build / obj, then the dependency file directory can be set to build / deps, and this correspondence makes the two directories logically associated. Path construction takes advantage of the string processing functions and variable reference mechanism in makefile. The dependency directory path can be generated by pattern substitution such as DEP_DIR := $(patsubst % / obj,% / deps,$(OBJ_DIR)), or directly defined as DEP_DIR := $(OBJ_DIR) / .. / deps, etc. The relative path form. The definition of the DEP_DIR variable is usually immediately after the definition of the OBJ_DIR variable, ensuring that the path configuration of the entire build system is centralized and consistent. In complex projects, you may also need to add rules to create the directory in the makefile to ensure that the dependency file storage directory exists before the compilation begins. This centralized path management greatly simplifies the maintenance of the build system, and when the directory structure needs to be adjusted, only a few variable definitions need to be modified.
[0068] In the original compilation rule, the dependency file is usually generated in the same location as the object file, and redirection can be achieved by specifying a new file path after the -Wp, -MD parameter. To achieve this, the prefix parameter needs to be added to the compilation rule, and the output path of the dependency file needs to be modified. GCC and other compatible compilers support specifying the specific output path of the dependency file through variants of the -MD parameter. The dependency file generation part in the compilation rule can be modified from the original -Wp, -MD, $(dir $@).$(notdir $@).d to -Wp, -MD, $(DEP_DIR) / $(notdir $@).d. This modification ensures that all dependency files are centrally output to a unified directory, rather than being scattered in the object file directory corresponding to each source file. In actual operation, the directory creation timing needs to be considered, and a dependency on the DEP_DIR directory can be added to the compilation rule to ensure that the directory exists before the dependency file is generated. For large projects, further subdirectories can be created in the dependency directory according to modules to form a more hierarchical file storage structure. This refined management can further improve the maintainability of the build system.
[0069] By implementing centralized storage management of dependency files, the organization and maintainability of the build system are significantly improved, the directory structure of the build product is made clearer, and file management is more orderly; the implementation of the cleaning operation is simplified, and specific types of build products can be accurately cleaned; the monitoring and debugging of the build system are facilitated, and developers can quickly locate and analyze dependency relationship information; the scalability of the build system is enhanced, laying a good foundation for the addition of more complex build management functions in the future; and the team collaboration efficiency is improved, and the unified file organization method reduces problems caused by environmental configuration differences.
[0070] In another technical solution, step S4 further includes the following dependency relationship integration step: By adding an include instruction in the makefile file to import the automatically generated dependency relationship file, the include instruction uses the wildcard function to match all dependency relationship files with the.d suffix under the object file output directory; adding a minus prefix before the include instruction makes the make tool ignore the dependency relationship file that has not been generated when compiling for the first time; Wrap the conditional statement around the include instruction, which will only execute the include operation when the dependency relationship file exists. The conditional statement is obtained by combining ifneq and wildcard functions.
[0071] The dependency files (.d files) contain detailed dependency information between source files and header files, which are crucial in the incremental compilation process. They tell the make tool which source files need to be recompiled when a header file changes. However, these.d files are generated dynamically during the compilation process and do not exist at the first compilation. The include directive of the make tool is used to include external file content into the current makefile during the parsing phase. However, if the included file does not exist, the make tool usually reports an error and stops execution. To solve this problem, a minus prefix is added before the include directive, which tells the make tool not to terminate the build when an include error is encountered, but to continue execution. In actual use, the include directive can be written in the form of -include $(DEP_FILES), where DEP_FILES is a variable that matches all.d files through the wildcard function. This design allows the first compilation to successfully pass the parsing phase and enter the actual compilation process, and generates the required dependency files during the compilation process.
[0072] Further enhanced by a conditional judgment statement wrapped around the include directive, specifically using the combination of ifneq and wildcard functions to check if the dependency file exists. This conditional inclusion mechanism is more accurate and efficient than simply prefixing a minus, as it completely avoids the warning information generated when the make tool attempts to include a non-existent file. The wildcard function expands during the makefile parsing phase and returns a list of files matching the specified pattern, or an empty string if no files match. The ifneq conditional judgment then checks if this result is non-empty, and only performs the include operation when the.d file actually exists. In actual implementation, the code can be presented as ifneq ($(wildcard $(DEP_DIR) / *.d),) include $(DEP_DIR) / *.d endif such structure. This conditional inclusion mechanism is particularly suitable for post-cleaning rebuild scenarios. After executing make clean, all.d files are deleted. The first build skips the include when the conditional judgment is false, and the.d files are generated during the build process. Subsequent builds have the conditional judgment true, and the dependencies are correctly included. This intelligent inclusion strategy ensures reliable operation of the build system in various situations.
[0073] The complete process of dependency integration includes three steps: generation, inclusion and application. In the generation step, the corresponding.d file is generated by the -Wp, -MD parameter when compiling each source file; in the inclusion step, these.d files are introduced into the makefile through conditional inclusion instructions; in the application step, the make tool determines the scope of incremental compilation by using the introduced dependencies. These three steps form a complete dependency management closed loop. The.d file is essentially a code snippet in makefile format, which defines the dependencies between source files, object files and header files. When included in the main makefile, these dependency rules become part of the entire build system. If a header file is modified, the make tool will automatically recompile all source files that depend on the header file based on the dependencies recorded in the.d file, ensuring the correctness of the build result. To handle exceptional cases, more complex error handling logic can be added around the inclusion instruction, such as triggering the regeneration of dependencies when the.d file content is corrupted or has a format error. For distributed build environments, synchronization and caching strategies for dependency files need to be considered to ensure consistency of dependency information across different build nodes.
[0074] By implementing automatic integrated management of dependencies, the intelligence and reliability of the build system are significantly improved, enabling true incremental compilation and greatly improving the efficiency of daily development. A perfect error handling mechanism is provided to ensure that the build system runs stably in various situations. The maintenance burden of dependency management is reduced, and developers do not need to manually maintain complex header file dependencies. The accuracy of the build result is ensured by automatically tracking file dependencies and triggering necessary recompilation. This provides key technical support for rapid iterative development of large projects, making the build feedback after code modification more timely.
[0075] The present application also provides a method for compiling and building multiple code projects, which includes the following steps: The code project automatic compilation and building method provided by any of the above solutions does not require specifying the path of each source code file. In each sub-code project directory of the multiple code projects, a makefile file for compiling and building the sub-code project is created and configured; A top-level makefile is created in the parent directory of all sub-code projects, and the compilation and building process of each sub-project is called in sequence by the shell statement make -C<sub-code project path> in the top-level makefile. All sub-projects are synchronously compiled and built by executing a single make command directly in the top-level directory.
[0076] In complex software development, a complete software product is usually composed of multiple relatively independent sub-projects, which can include core algorithm library, user interface module, data persistence layer, network communication module, etc. Each sub-project has an independent code organization structure, compilation requirements and output target, but needs to work together to build the final complete product. This multi-project collaborative construction architecture design solves the limitations of traditional single-project construction method in complex projects. Multi-project construction adopts the design idea of divide and conquer, which divides the huge software system into multiple relatively independent construction units. Each sub-project can use the automatic compilation and construction method provided by the present application to create an independent makefile file in its own directory. These sub-project makefiles are responsible for managing the collection of source files, compilation rules, dependency processing and module target generation of the module. In actual implementation, the division of sub-projects can be based on multiple dimensions such as function modules, development teams, technology stacks or release units, for example, a large project can be divided into core engine, front-end interface, plug-in system and other sub-projects. Each sub-project can be developed, tested and constructed independently, and this architecture greatly improves the manageability and team collaboration efficiency of large projects.
[0077] The top-level makefile plays the role of the overall commander of the construction, and it does not directly participate in the specific compilation work, but calls the construction process of each sub-project in turn through the -C parameter of the make command. This design forms a typical master-slave construction architecture. make -C <directory>The command instructs the make tool to switch to the specified directory and execute the makefile in that directory, and after execution, return to the current directory to continue subsequent operations. The top-level makefile usually contains a series of such call statements. The top-level makefile can define unified build targets (such as all, clean, install, etc.), and when the user executes make all in the top-level directory, the top-level makefile will sequentially call the corresponding targets of each sub-project. This coordination mechanism ensures the orderliness and integrity of the build process. To enhance flexibility, the top-level makefile can also pass build configuration information to the sub-projects through environment variables or command line parameters, such as target platform, optimization level, debugging options, etc., to achieve unified build strategy management.
[0078] The key to multi-project synchronous compilation and build is the organization and execution order of each sub-project build task, which can be directly performed in the top-level directory by executing a single make command to synchronize the compilation and build of all sub-projects, which involves the scheduling and optimization of build tasks. Synchronous compilation not only means that the user only needs to execute a command once, but also requires the system to intelligently handle the dependency relationships and build order between sub-projects. The top-level makefile can implement the coordinated build of sub-projects in multiple ways. The simplest is the serial execution method, which builds sub-projects one by one in the order of dependency; the more efficient is the parallel execution method, which uses the -j parameter of make to concurrently build independent sub-projects; the most intelligent is the dependency-driven method, which dynamically determines the build order by analyzing the actual dependency relationships between sub-projects. In actual implementation, the dependency relationships between sub-projects can be defined in the top-level makefile, for example, setting "subproject2: subproject1" to indicate that subproject2 depends on the build results of subproject1. For large projects, a build cache and incremental detection mechanism can also be introduced to avoid repeated building of unchanged sub-projects. In addition, the top-level makefile can provide unified progress display, error handling, and log recording functions, allowing developers to clearly understand the overall build status and problem positioning.
[0079] Through the design of the multi-project coordinated build architecture, a comprehensive solution is provided for the build management of complex software systems, greatly simplifying the build management of multi-module projects, controlling the build process of all sub-projects through a single entry point; significantly improving the build efficiency of large projects, shortening the overall build time through reasonable task scheduling and parallel processing; enhancing the clarity and modularity of the project structure, supporting parallel development and independent testing of teams; providing flexible scalability, with the addition of new sub-projects only requiring the addition of corresponding calls in the top-level makefile; reducing the maintenance cost of the build system, and the unified coordination mechanism avoids inconsistency problems in the build configuration of each sub-project.
[0080] In another technical solution, the code engineering is divided into a hardware abstraction layer and an application layer, and the following method is used for hierarchical compilation and construction of the code: The hardware abstraction layer code files and the application layer code files are respectively stored in a hardware abstraction layer code subdirectory and an application layer code subdirectory of the code engineering; A first makefile is created in the hardware abstraction layer code subdirectory, for compiling the hardware abstraction layer code files into hardware library files; A second makefile is created in the application layer code subdirectory, for compiling and linking the hardware library files and the application layer code files together into an executable application program; A top-level makefile is created under the general directory of the code engineering, and the hardware abstraction layer and the application layer code are automatically compiled and constructed in an integrated manner by nested calling of the first makefile and the second makefile.
[0081] In embedded system development, the separation of hardware abstraction layer (HAL) and application layer is a classic and important design pattern. The hardware abstraction layer is responsible for encapsulating operations related to specific hardware platforms and providing a unified hardware access interface; the application layer implements specific business logic and functional algorithms based on these interfaces, without needing to concern the specific details of the underlying hardware. This layered design greatly improves the portability and maintainability of embedded software. The hardware abstraction layer isolates the differences of hardware at the bottom layer through interface abstraction and driver encapsulation. For example, for different microcontroller models, peripheral configurations, or sensor types, the hardware abstraction layer provides uniform API interfaces such as gpio_set(), uart_send(), adc_read(), etc. Application layer code is developed entirely based on these standard interfaces, and when porting to a new hardware platform, only the hardware abstraction layer needs to be replaced or adapted, and the application layer code basically does not need to be modified. The hardware abstraction layer is usually further subdivided into board support packages (BSP), device driver layers, operating system abstraction layers, and more detailed layers, forming a complete embedded software stack. This layered architecture is the key technical foundation for modern embedded systems to quickly adapt to multiple hardware platforms and support product line diversification.
[0082] The hardware abstraction layer code files are centrally stored in a dedicated hardware abstraction layer code subdirectory, such as the hal / , bsp / , or drivers / directory, and a first makefile is created in the directory to compile the hardware abstraction layer code into hardware library files. These library files can be static libraries (.a files) or dynamic libraries (.so files), and the specific choice depends on system requirements and resource constraints. The compilation process of the hardware abstraction layer focuses on producing reusable hardware access components. The first makefile uses the automatic compilation method provided in the present application to collect all hardware-related source files, compile object files, and finally package the library files using tools such as ar or gcc. The application layer code is stored in another separate subdirectory, such as app / or application / , and a second makefile in the subdirectory is responsible for compiling and linking the hardware library files and application layer code files together into an executable application program. During the linking process, the second makefile needs to specify the search path of the hardware library files through the -L parameter and link specific library files through the -l parameter. The application layer makefile needs to know the generation location and interface definition of the hardware library files, which is usually achieved through header file inclusion paths and library file path variables. This clear separation of responsibilities allows the development of the hardware layer and the application layer to be relatively independent, which is particularly suitable for scenarios where hardware and software teams develop in parallel.
[0083] The goal of this scheme is to achieve integrated automatic compilation and construction of the hardware abstraction layer and application layer code, which is achieved through nested calls of the top-level makefile. A top-level makefile is created under the total directory of the code project, which coordinates the calling of the first makefile and the second makefile through specific rules and dependencies to form a complete construction pipeline. The top-level makefile defines two main construction targets: the hardware abstraction layer construction target and the application layer construction target, and explicitly sets the application layer construction to depend on the hardware abstraction layer construction. When the user executes the top-level make command, the construction system first switches to the hardware abstraction layer directory to execute the first makefile to generate hardware library files; then switches to the application layer directory to execute the second makefile to link the newly generated hardware library with the application code into the final executable program. In actual implementation, the top-level makefile also needs to handle details such as path passing, environment setting, error recovery, etc. For example, the library file path generated by the hardware abstraction layer needs to be passed to the application layer makefile; if the hardware abstraction layer construction fails, the entire construction process should be aborted; clear progress prompts and result feedback should be provided during the construction process. For complex embedded projects, additional functions such as firmware packaging, burning script generation, etc. can be added to the top-level makefile to form a complete embedded software development solution.
[0084] The implementation of the layered compilation construction method provides a highly automated and modularized construction solution for embedded system development, greatly improves the portability of embedded software, enables the application code to quickly adapt to different hardware platforms through the isolation of the hardware abstraction layer, significantly enhances the reusability and maintainability of the code, limits hardware-related modifications to the abstraction layer and does not affect the upper-layer application logic, supports parallel development of hardware and software teams, improves project development efficiency, provides an integrated automatic construction process, forms a complete construction chain from the bottom-layer driver to the upper-layer application, reduces the technical threshold for embedded system development, and reduces configuration errors and compatibility problems through standardized construction methods.
[0085] It should be noted that although the above describes the steps in a specific order, it does not mean that the steps must be performed in the above specific order, in fact, some of the steps can be performed concurrently or even in reverse order, as long as the desired function can be achieved. The number of devices and the size of the processing described herein are used to simplify the description of the present application, and the application, modification and variation of the present application are obvious to those skilled in the art.
[0086] Although the embodiments of the present application have been disclosed as above, they are not limited to the application and implementation listed in the specification and embodiments, and can be fully applied to various fields suitable for the present application, and additional modifications can be easily realized by those skilled in the art, therefore the present application is not limited to specific details and the figures shown and described herein, without departing from the general concept defined by the claims and the equivalent scope.< / directory>
Claims
1. A method for automatically compiling and building code projects without specifying the path to each source file individually, characterized by: Includes the following steps: S1: Create a makefile in the code project path. In the makefile, create a shell variable DIR_PROJECT to store the relative path of the code project storage location to the makefile storage location. Create a shell variable CC to store the absolute path of the compiler that compiles the code project. Create a shell variable APP to store the generation path of the final executable binary file. S2: Create folders with the same name, src and inc, in each directory of the code project. The src folder is used to store all source files in that directory, and the inc folder is used to store all header files in that directory. S3: Perform the following configuration operations by adding shell statements to the Makefile: S301: Search all src folders under the code project path DIR_PROJECT, obtain the folder paths where all code source files are located, and save them to the shell variable src_dirs; S302: Search for all inc folders under the code project path DIR_PROJECT, obtain the folder paths of all code header files, and save them to the shell variable inc_dirs; S303: Retrieve the file extensions of all source code files in all folder paths saved in the shell variable src_dirs, obtain the full paths of all source code files, and save them to the shell variable srcs; S304: Replace the full path of all source files in the shell variable srcs with the suffix .o, obtain the generated paths of the object files corresponding to all source files, and save them to the shell variable objs; S4: Add compilation rules to the Makefile to use the compiler specified by the shell variable CC to compile each source code file in the shell variable srcs and generate the corresponding object file. When compiling, add the compilation parameter -I to specify the shell variable inc_dirs as the header file search path, and add the compilation parameters -Wp, -MD to automatically generate dependency files. S5: Add a linking rule to the makefile file. When building the source code project, use the compiler specified by the shell variable CC to link all object files in the shell variable objs with the required library files to generate an executable binary file. S6: Add a build rule to the Makefile. When building the source code project, execute the makeclean command to delete all object files, dependency files, and executable binary files generated during the compilation process.
2. The method for automatically compiling and building code projects without specifying the path of each source file as described in claim 1, characterized in that, In step S3, the shell statements used for path retrieval and file list generation are as follows: The statement used in step S301 is: src_dirs := $(shell find $(DIR_PROJECT) -type d -namesrc); The statement used in step S302 is: inc_dirs := $(shell find $(DIR_PROJECT) -type d -nameinc); The statement used in step S303 is: srcs := $(foreach dir, $(src_dirs), $(wildcard $(dir) / *.c)); The statement used in step S304 is: objs := $(patsubst %.c, %.o, $(srcs)).
3. The method for automatically compiling and building code projects without specifying the path of each source file as described in claim 1, characterized in that, In step S4, the compilation rules in the makefile are specifically the following pattern rules: %.o : %.c $(CC) -Wp,-MD,$(dir $@).$(notdir $@).d -c -o $@ $< $(foreach dir, $(inc_dirs), -I$(dir)) The paths to dependency files are automatically generated by combining $(dir $@) and $(notdir $@).d.
4. The method for automatically compiling and building code projects without specifying the path of each source file according to claim 1, characterized in that, In step S5, the linking rules in the makefile are specifically the following pattern rules: ${APP}:$(objs) $(CC) $^ -o $@.
5. The method for automatically compiling and building code projects without specifying the path of each source file as described in claim 1, characterized in that, In step S5, during linking, the POSIX pthread thread library and the multi-threaded C runtime library are linked by adding the linking parameter -pthread, and / or the real-time library is linked by adding the linking parameter -lrt.
6. The method for automatically compiling and building code projects without specifying the path of each source file as described in claim 1, characterized in that, In step S6, add the declaration .PHONY: clean to the makefile file to declare the clean label as a pseudo-target to avoid conflicts caused by the existence of a file named clean with the same name as the label in the directory where the makefile is located.
7. The method for automatically compiling and building code projects without specifying the path of each source file as described in claim 1, characterized in that, In step S4, the generated dependency files are also stored in a separate directory from the object files by modifying the generation path of the dependency files. This specifically includes the following steps: Add a prefix parameter to the compilation rule to point the generation path of the dependency files to a specific dependency file subdirectory under the output directory of the object files. Create a shell variable DEP_DIR in the makefile to store the path of this dependency file subdirectory. The path of the dependency file subdirectory is obtained by replacing the suffix based on the generation path of the object files. Store the dependency files corresponding to each source file in the same dependency file directory.
8. The method for automatically compiling and building code projects without specifying the path of each source file as described in claim 1, characterized in that, Step S4 also includes the following dependency integration steps: Automatically generated dependency files are included by adding include directives to the Makefile. These include directives use the wildcard function to match all dependency files with the .d suffix in the object file output directory. Adding a minus sign prefix before the include directive causes the make tool to ignore dependency files that have not yet been generated during the first compilation. The include operation is performed only if the dependency file exists, and the conditional statement is obtained by combining the ifneq and wildcard functions.
9. A compilation and build method for multi-code projects, characterized in that, Includes the following steps: The automatic compilation and building method for code projects that does not require specifying the path of each source code file according to any one of claims 1 to 8, wherein makefile files for compiling and building the sub-code projects are created and configured in each sub-code project directory of the multi-code project; Create a top-level makefile in the parent directory of all sub-code projects, and use the shell statement `make -C <sub-code project path>` to sequentially call the compilation and build process of each sub-project. Then, execute a single `make` command directly in the top-level directory to compile and build all sub-projects synchronously.
10. The compilation and construction method for a multi-code project according to claim 9, characterized in that, The code project is divided into a hardware abstraction layer and an application layer, and the following methods are used to compile and build the code in layers: Store the hardware abstraction layer code files and the application layer code files in the hardware abstraction layer code subdirectory and the application layer code subdirectory of the code project, respectively; Create the first makefile in the Hardware Abstraction Layer code subdirectory to compile the Hardware Abstraction Layer code files into hardware library files; Create a second makefile in the application layer code subdirectory to compile and link the hardware library files and application layer code files together into an executable application; A top-level makefile is created in the main directory of the code project, and the hardware abstraction layer and application layer code are automatically compiled and built in an integrated manner by nesting the first makefile and the second makefile.
Citation Information
Cited By
Method and device for automatically compiling and uploading java file
CN121658011A