Msbuild deep understanding classification: topic development automation 5711 people read comments (1) collect Report Task engine script work extension build
Recently, in the process of automatic construction, we have a deeper understanding of msbuild itself. Msbuild is not just a construction tool, it should be called an automation platform with powerful scalability.
According to my understanding, the msbuild platform mainly involves three parts: execution engine, construction project, and task. The core of the construction is the execution engine, which includes defining the constructor specification, interpreting the constructor, and executing the "constructor action". The constructor is used to describe the constructor, in most cases, we use msbuild to follow the rules and write a constructor. Each "constructor action" executed by the msbuild engine is implemented by a task, and the task is the Extended Mechanism of msbuild, by writing new tasks, you can continuously expand the execution capability of msbuild.
Therefore, these three parts represent the engine, script, and expansion capabilities.
1. Construct a project (script file)
Let's talk about the constructor. As long as you open any C # project (csproj) file under vs2005 (that is, CLR 2.0 is supported) through notepad, you will know what is going on in the constructor.
If we say a script, we immediately think of VBScript or JavaScript to construct the content described in the project. There is still a big gap between it and the source files of common scripting languages, why is it also called "script? Because I think there is no difference. A script is not saved in plain text format, but executed without compilation or interpretation. Can a program with a certain logic Branch be implemented?
Let's look at the constructor again. In the constructor, we can define and use variables (through elements such as property/propertygourp/item/itemgroup ), you can use conditional branches (through elements such as choose, when, and otherwise) to assign values to variables during runtime (by executing tasks, you can obtain the return type parameters) can define execution blocks (through the target element, which is equivalent to a function), can handle exceptions (through the onerror element), and can reuse the content defined by an existing project (through the import element ). These capabilities are almost the same as advanced languages. Therefore, I believe that constructor is not a descriptive language, but a scripting language.
It must be emphasized that the project-level elements (properties) can be defined under the <propertygroup> element, it can also be passed in as an external parameter during the construction process (for details, see msbuild command line reference). This is a very useful feature. This feature is usually used to select a configuration item (debug or release) during compilation.
For the compilation specifications of the constructor, refer to msbuild project file reference.
2. execution engine
Next, let's look at the execution engine. Generally, we use the following command line to start the execution structure:
Msbuild.exe <projectfile>
Where<Projectfile>Is the structure project mentioned above, and also contains the script file. msbuild.exe should be the execution engine.
If there is no error, you can find that msbuild.exe is very simple. In fact, the main task is to prepare the command line parsing and Environment Construction (for example, to prepare some global variables for the log generation module), and then create Microsoft. build. buildengine. engine class instance, and then call its buildprojectfile method to complete. Therefore, the real construction logic is defined and implemented in Microsoft. Build. Engine. dll. The simple code below simulates the work of msbuild.exe.
[C-sharp]View plaincopy
- Using system;
- Using system. Collections. Generic;
- Using system. text;
- Using Microsoft. Build. buildengine;
- Namespace buildaprojectcs
- {
- Class Program
- {
- Static void main (string [] ARGs)
- {
- // Instantiate a new engine object
- Engine engine = new engine ();
- // Point to the path that contains the. NET Framework 2.0 Clr and tools
- Engine. binpath = @ "C:/Windows/microsoft.net/framework/v2.0.xxxxx ";
- // Instantiate a new filelogger to generate build log
- Filelogger logger = new filelogger ();
- // Set the logfile parameter to indicate the log destination
- Logger. Parameters = @ "logfile = C:/temp/build. log ";
- // Register the logger with the engine
- Engine. registerlogger (logger );
- // Build a project file
- Bool success = engine. buildprojectfile (@ "C:/temp/validate. proj ");
- // Unregister all loggers to close the log file
- Engine. unregisterallloggers ();
- If (SUCCESS)
- Console. writeline ("build succeeded .");
- Else
- Console. writeline (@ "build failed. View C:/temp/build. log for details ");
- }
- }
- }
For specific object models, see Microsoft. Build. Framework namespace and Microsoft. Build. buildengine Command Space in the CLR class library reference.
The author simply analyzed the source code of msbuild.exe and Microsoft. Build. Engine. dll. The msbuild construction process is roughly as follows:
A) first create a constructor request (buildrequest, constructor request is used to record the data structure of the constructor State). After the constructor is created, the constructor request is shipped to the Request queue.
B) In the execution module, obtain the request from the request queue and start processing.
C) load the construction project through the project class, and check whether the project is sulotion, VC project, or other languages during the loading process. If it is solution, a temporary packaging project is generated to construct the project included in solution one by one. If it is a VC project, a packaging project is also generated, execute the vcbuild task in this project to execute the construction. Otherwise, you can directly load the project file through xmldocument, parse the elements in the file, and identify elements such as property, item, and target.
D) after the project resolution is completed, it will be executed one by one according to the target sequence.
E) check whether the target and the onerror clause are dependent during target execution (that is, the target to be executed when an error is generated ).
F) first execute the target on which the target depends, and then execute each task in the target through taskengine. If each target task is correctly executed, execute the next target; otherwise, execute the target for error handling.
G) the process of executing a task is to instantiate the class registered as a task and call its execute method.
H) after all the targets are executed, the construction is also completed.
As described above, the actual construction process may take into account multiple CPUs and inline compilation. The internal logic is quite complex and the proxy mode is applied in many places.
3. Task)
Through the description of the execution engine, we can find that the execution engine mainly maintains the execution process and records various variables (properties and items) in the execution process. Each action in the construction process is shown, all are implemented through tasks. Microsoft. Build. Engine. dll alone can load and parse the constructor, but cannot complete the constructor action. The reason why msbuild can complete compilation, linking, creating directories, copying files, and so on is that the corresponding tasks are implemented in Microsoft. Build. Tasks. dll. For details, refer to msbuild task reference and Microsoft. Build. Task namespace in CLR class library reference.
By observing these common tasks inherent in msbuild, we can find that there are two types: one is inherited from the tooltask, which basically calls the external binary file directly to execute a specific action, for example, vcbuild and exec. Another type of inheritance directly from the task is to complete specific actions through the internal code logic, such as copy and msbuild. Although the tasks that directly execute external files are powerful, they have relatively large limitations. The feedback on execution results is very limited. Generally, only exitcode is available, which makes it difficult to obtain more information about internal execution, for example, log output or operation impact results.
In most cases, we only need one exec task to complete all the construction actions, but the result is no different from the batch file we write a command line. The major difference between the msbuild platform and the command line batch processing is that it is a closer working environment, and tasks work together through a series of custom global parameters, which is flexible and highly portable; at the same time, the Log Module outputs all types of information during execution to facilitate observation and analysis. In batch processing, commands are almost completely isolated and can only be used for hard-coded collaboration, with poor collaboration capabilities.
For example, compile three projects and copy the compilation results to the target directory. If you use batch processing, it may look like this: "compile project 1. Copy compilation results, compile project 2. Copy results, compile project 3. Copy results ". Using msbuild can simplify a lot of work, for example, "declare the project to be compiled (Project 1, Project 2, project 3 ,...), compile the project to be compiled, copy the compilation result ".
By the way, the msbuild task is interesting, and the internal method of constructing the engine is called directly (ibuildengine2.buildprejectfilesinparallel ). This example once again tells us that there are many seemingly powerful things in this world, but they have nothing to do, just because they have mastered effective resources. -^ O ^-
In addition to basic tasks, tasks can also be expanded as needed, which is very convenient to implement. Create a class library project with CLR 2.0 or above, write a class that implements the itask interface, and then register the task through the <usingtask> element in the constructor. For example:
[XHTML]View plaincopy
- <Usingtask taskname = "Microsoft. compactframework. Build. Tasks. platformverificationtask" assemblyname = "Microsoft. compactframework. Build. Tasks, version = 9.0.0.0, culture = neutral, publickeytoken = snapshot"/>
- ......
- <Target name = "platformverificationtask">
- <Platformverificationtask
- Platformfamilyname = "$ (platformfamilyname )"
- Platformid = "$ (platformid )"
- Sourceassembly = "@ (intermediateassembly )"
- Referencepath = "@ (referencepath )"
- Treatwarningsaserrors = "$ (treatwarningsaserrors )"
- Platformversion = "$ (targetframeworkversion)"/>
- </Target>
Therefore, msbuild can become a constructor, not because of an EXE file named msbuild, or because a script file is called a constructor, but because of its supporting Microsoft. build. task. DLL mainly implements the construction-related tasks. In other words, msbuild is an automatic testing platform if the task library related to the test is provided.
In short, msbuild tends to be an automated execution platform. Different script files can be written as needed to meet different applications. When the existing capabilities cannot be met, by writing new tasks for extension. It is not limited to construction. Automatic Installation and automatic testing can all rely on this platform.