Source Configuration Architecture: Difference between revisions
(Updated now I understand Visual Studio project layout a little better) |
(Clarify need to generateProjectFiles a second time) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 22: | Line 22: | ||
The project files – delivery\projects\*\*.csproj and *.sln – define the different Projects within the overall Solution for the different development environments and the msbuild compiler. To build them, first namespace.map and the source code are analysed to create project.map and projectuuid.map in delivery\projects. The former contains all the project References; the latter, the GUIDs (used internally by the IDE). These in turn are used to build the final project and solution files. New GUIDs are created as necessary. Like generating namespace.map, this is written as a dependency within NAnt to ensure it happens as needed. | The project files – delivery\projects\*\*.csproj and *.sln – define the different Projects within the overall Solution for the different development environments and the msbuild compiler. To build them, first namespace.map and the source code are analysed to create project.map and projectuuid.map in delivery\projects. The former contains all the project References; the latter, the GUIDs (used internally by the IDE). These in turn are used to build the final project and solution files. New GUIDs are created as necessary. Like generating namespace.map, this is written as a dependency within NAnt to ensure it happens as needed. | ||
If you add new files to a project (or updating your branch pulls in new files) then Visual Studio won't be able to build the project properly until the project file is updated too. | If you add new files to a project (or updating your branch pulls in new files) then Visual Studio won't be able to build the project properly until the project file is updated too. Note that the first time you do this on a new branch, it will warn you that it doesn't know where to put all the files. That's normal: a lot of the code it needs will be generated in the following steps. The first pass generates the project files to build the tools; those tools then build the remainder of the code and after that you generate the project files again to complete the solution. | ||
<code>nant generateProjectFiles</code> | <code>nant generateProjectFiles</code> | ||
Line 66: | Line 66: | ||
==The Glue== | ==The Glue== | ||
The "glue" is the set of interfaces and instantiators between the client and server. This parses .cs files for namespaces | The "glue" is the set of interfaces and instantiators between the client and server. This parses .cs files for methods in the Remoting namespaces, such as WebConnectors, and produces Shared\lib\Interfaces\*Interfaces-generated.cs, Server\lib\*\connect\Instantiator.AutoHierarchy-generated.cs, and Server\lib\*\connect\Instantiator.Connectors-generated.cs. The interfaces-generated.cs files together make up the Ict.Petra.Shared.lib.Interfaces project in the development environment. Some of the Project References and using statements can be calculated automatically, but others need to be specified manually. You do this in the file csharp\ICT\Petra\Shared\lib\Interfaces\InterfacesUsingNamespaces.yml. When you add a namespace against an interface here, it will be added to the generated file's using statements, and its project will be added to the Interfaces project's Reference list. | ||
<code>nant generateGlue</code> | <code>nant generateGlue</code> | ||
Line 76: | Line 76: | ||
==The SOLUTION!== | ==The SOLUTION!== | ||
Now all the generated project files, forms, datasets, tables, access code, interfaces, instantiators etc. are in place, we can use msbuild to compile the entire application from the generated OpenPetra.sln solution file (NAnt drives msbuild for us, no need to know about it in detail!). | Now all the generated project files, forms, datasets, tables, access code, interfaces, instantiators etc. are in place, we must run <code>nant generateProjectFiles</code> again to complete the set of project files. Then we can use msbuild to compile the entire application from the generated OpenPetra.sln solution file (NAnt drives msbuild for us, no need to know about it in detail!). | ||
If anything changes that the generated code or manually written code depends upon, remember to regenerate the appropriate code before recompiling (with <code>nant quickCompile</code>) with either the single steps lined out above, or by using | If anything changes that the generated code or manually written code depends upon, remember to regenerate the appropriate code before recompiling (with <code>nant quickCompile</code>) with either the single steps lined out above, or by using |
Latest revision as of 11:48, 11 Mayıs 2017
OpenPetra is a very large and complex project. Several parts of it are automatically generated by other parts. The easiest way to understand how it all fits together is to take a bird's-eye view of the build process. In real life, this is handled automatically by clicking "Generate Solution" in the OpenPetra Developers' Assistant, or by typing "nant generateSolution" at the command prompt in a newly checked-out working directory.
OpenPetra uses NAnt as its build tool. NAnt uses buildfiles containing lists of Targets and the instructions to build those Targets. The default buildfile is the first *.build file in the current directory; in our case that would be OpenPetra.build at the top of the working directory tree. We have defined many NAnt Tasks for OpenPetra, some of which are listed on this page.
By opening up what happens during Generate Solution, we can see what all the generated code is, where it comes from, and how to control it.
Detailed reference, with some more "How-To's": Build system with our own NAnt tools and tasks
The Version Number
The first thing to do is pull the Bazaar version info for the current branch into delivery\bin\vcs-revision.txt. Now it can be included in the source code and displayed in the application.
nant pullVCSVersionInfo
The Namespace Map
OpenPetra was designed to support different development environments: Visual Studio, SharpDevelop and MonoDevelop. The project and solution files differ between these systems, and we don't store them in the project repository; they are generated dynamically from the source code. The first part of this process is to generate delivery\projects\namespace.map. This file links every namespace defined in the project files with the default namespace of the project it belongs to. The generateNamespaceMap task is a dependency of the NAnt build tasks and will happen as needed.
For example, the Ict.Petra.Server.lib.MCommon project contains the Ict.Petra.Server.MCommon, Ict.Petra.Server.MCommon.Cacheable, and several other namespaces.
The Project Files
The project files – delivery\projects\*\*.csproj and *.sln – define the different Projects within the overall Solution for the different development environments and the msbuild compiler. To build them, first namespace.map and the source code are analysed to create project.map and projectuuid.map in delivery\projects. The former contains all the project References; the latter, the GUIDs (used internally by the IDE). These in turn are used to build the final project and solution files. New GUIDs are created as necessary. Like generating namespace.map, this is written as a dependency within NAnt to ensure it happens as needed.
If you add new files to a project (or updating your branch pulls in new files) then Visual Studio won't be able to build the project properly until the project file is updated too. Note that the first time you do this on a new branch, it will warn you that it doesn't know where to put all the files. That's normal: a lot of the code it needs will be generated in the following steps. The first pass generates the project files to build the tools; those tools then build the remainder of the code and after that you generate the project files again to complete the solution.
nant generateProjectFiles
The Tools
The next thing to do is build the tools that are used in the remainder of the build process. This includes the following files:
- delivery\bin\Ict.Tools.CodeGeneration.dll
- delivery\bin\Ict.Tools.GenerateWinForms.exe
- delivery\bin\Ict.Tools.GenerateSQL.exe
- delivery\bin\Ict.Tools.GenerateORM.exe
- delivery\bin\Ict.Tools.GenerateGlue.exe
as well as come Common code needed by the tools.
nant generateTools
The Forms
OpenPetra's forms and user controls are defined in .yaml files. This step parses petra.xml and the form & control .yaml files to build them into the C# *-generated.Designer.cs and *-generated.cs files required by the compiler.
A form's -generated.cs code is supplemented by a .ManualCode.cs file to handle specific processing. If you add a new method to a form's .ManualCode.cs file, it won't be called unless you regenerate the form (see Documentation YAML for OpenPetra Forms#ManualCode)! In certain cases one also needs to add the appropriate section to the form's .yaml file and regenerate the form. For example, to add verification code to a report, you add a ReadControlsVerify() method. But you also need to add the corresponding READCONTROLSLOCALVARS to the TemplateParameters section of the .yaml and regerate the form, or the call won't be included in the main generated code.
nant generateWinforms
The Object-Relational Model
The Object-Relational Model (ORM) is the Data Access Layer for accessing the DB data in a typesafe way by creating typed data tables, typed datasets and typed access classes that provide convenient access to them. There are 4 parts to the process:
- generateORMCachedTables
- Generates the cached tables.
- Parses csharp\ICT\Petra\Shared\lib\data\*.TypedDataSets.xml to produce *Cacheable-generated.cs
- Details: Documentation Cacheable Tables
- generateORMData
- Generates the files for Ict.Petra.Shared.lib.data, ie. the typed tables and typed datasets.
- Parses typed table namespaces, validation and datasets to produce *Tables-generated.cs, *Validation-generated.cs, *DataSets-generated.cs
- generateORMAccess
- Generates the files for Ict.Petra.Server.lib.data, ie. the access files for reading from and writing to the database.
- Parses typed table namespaces and datasets to produce *Access-generated.cs and Cascading-generated.cs
- generateORMReferenceCounts
- Generates the server web connector classes that perform table reference counting.
- Parses *.yaml files and produces csharp\ICT\Petra\Server\lib\*\web\ReferenceCount-generated.cs
nant generateORM
The Glue
The "glue" is the set of interfaces and instantiators between the client and server. This parses .cs files for methods in the Remoting namespaces, such as WebConnectors, and produces Shared\lib\Interfaces\*Interfaces-generated.cs, Server\lib\*\connect\Instantiator.AutoHierarchy-generated.cs, and Server\lib\*\connect\Instantiator.Connectors-generated.cs. The interfaces-generated.cs files together make up the Ict.Petra.Shared.lib.Interfaces project in the development environment. Some of the Project References and using statements can be calculated automatically, but others need to be specified manually. You do this in the file csharp\ICT\Petra\Shared\lib\Interfaces\InterfacesUsingNamespaces.yml. When you add a namespace against an interface here, it will be added to the generated file's using statements, and its project will be added to the Interfaces project's Reference list.
nant generateGlue
The 3rd-Party DLLs
OpenPetra uses a number of 3rd-party DLLs. The vast majority of these are freely distributable and automatically included as part of the application; others can only be distributed under licence. This step is used where permitted to copy the licensed FastReport DLLs from the location specified by the FASTREPORT_DLL_PATH environment variable to delivery\bin.
nant copyFrDlls
The SOLUTION!
Now all the generated project files, forms, datasets, tables, access code, interfaces, instantiators etc. are in place, we must run nant generateProjectFiles
again to complete the set of project files. Then we can use msbuild to compile the entire application from the generated OpenPetra.sln solution file (NAnt drives msbuild for us, no need to know about it in detail!).
If anything changes that the generated code or manually written code depends upon, remember to regenerate the appropriate code before recompiling (with nant quickCompile
) with either the single steps lined out above, or by using
nant generateSolution
: this will execute all build steps lined up on this page in correct order and hence will ensure that all generated code and manually written code will be tied together. It is also a requirement to run this NAnt Task before a Branch gets committed to 'trunk' to ensure that the whole process runs through without any hiccups!
Developer's Assistant
Your reward for a successful build is the OpenPetra Developers' Assistant, which is built along with everything else. It provides an extremely helpful front-end and guide to NAnt and Bazaar so that you don't have to remember all these commands, and it manages all your database configurations. Find it in delivery\bin\Ict.Tools.DevelopersAssistant.exe and copy it to your desktop or somewhere. It maintains its settings in your AppData\Local folder, and updates itself automatically if it detects a newer copy of itself in your current branch.