Eclipse's managed build system enhances the usability and extensibility for C/C++ developers
January 31, 2007
URL:http://drdobbs.com/cpp/extending-the-eclipse-cdt-managed-build/197002115
Eclipse CDT 3.1 provides a host of improvements to the open-source CDT environment. Some of the improvements focus on greater performance and scalability, such as providing faster searches. Others reflect the CDT team's ongoing work to provide a better user experience for C and C++ developers, including better drag-and-drop support, improved syntax highlighting, and more accurate code refactoring.
The managed build system (MBS), in particular, contains many significant enhancements that improve both the usability and extensibility of the CDT build environment.
For CDT users, the updated MBS offers the ability to:
For tool integrators, the updated MBS offers:
In this article, we provide an example of how tool integrators can leverage some of the new capabilities of the MBS.
The CDT and the Java Development Tools (JDT) environment share many similarities, but they also differ in several ways. One of these differences is in how they build user projects.
Eclipse defines the concept of a project, which is an Eclipse resource. A project contains other Eclipse resources, specifically folders and files. A CDT project is a specialized Eclipse project that requires additional information to treat project resources as the source files of an application or library written in C/C++. One example is the set of include directories to be used when compiling the source files.
Eclipse also defines the concept of a builder and lets projects define which builder(s) they will use. CDT builders differ from JDT builders in two important ways:
To add functionality to Eclipse, you provide packages of Java code called plug-ins. Plug-ins "plug into" extension points defined by lower levels of the Eclipse architecture. A plug-in can define additional extension points, allowing hierarchical layers of functionality to be constructed. Most Eclipse functionality, including JDT and CDT, is provided in the form of plug-ins. For more information, see Contributing to Eclipse by Erich Gamma and Kent Beck.
A builder is embodied by the Eclipse builder extension point, org.eclipse.core.resources.builder. MBS plugs into this extension point in order to be invoked by Eclipse whenever a build of an MBS project is required. To implement an Eclipse extension point, you fill out a well-defined XML schema that is specific to the extension point (see Listing One for the MBS extension to the Eclipse builder extension point). Implementing an extension point also often involves implementing a particular Java interface or subclassing a public Java class. For instance, to implement an Eclipse builder extension point, you must define a subclass of the org.eclipse.core.resources.IncrementalProjectBuilder class.
<!-- ========================================================== -- > <!-- Extension Point: Makefile Generation Builder -- > <!-- ========================================================== -- > <extension id="genmakebuilder" name="%GeneratedMakefileCBuilder.name" point="org.eclipse.core.resources.builders"> <builder hasNature="true"> <run class= "org.eclipse.cdt.managedbuilder.internal.core.GeneratedMakefileBuilder"& gt; </run> </builder> </extension>
CDT provides two distinct builders: the Managed Make builder provided by MBS and the Standard Make builder. A CDT user begins the development process by creating a CDT project. At the onset of project creation, the user must decide whether to create a Standard Make project or a Managed Make project. Although both project types use GNU make to build the project, they are different. With Standard Make, the CDT user must provide makefiles to build the project; with Managed Make, MBS automatically generates the makefiles required.
To generate the makefiles for a project, MBS uses information from three sources:
You provide a tool-chain definition by plugging into the MBS tool definition extension point, org.eclipse.cdt.managedbuilder.core.buildDefinitions. The extension point defines an XML schema that lets you describe the tools in your tool-chain. See Figure 1 for the object model used by the schema. If you have access to the CDT source code, see org.eclipse.cdt.managedbuilder.core/schema/buildDefinitions.exsd.
The schema is used both by the MBS extension point and by the MBS-specific project file that stores the user's modifications to a project's properties. If you have an MBS project, examine the .CDtbuild file (see Listing Two for an example). MBS provides reference tool-chain definitions for GNU C/C++ on many different development platforms. If you have access to the CDT source code, see org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml.
<?xml version="1.0" encoding="UTF-8" ?> <?fileVersion 3.0.0?> <ManagedProjectBuildInfo> <project id="HelloWorld.cdt.managedbuild.target.gnu.cygwin.exe.554942561" name="Executable (Gnu on Windows)" projectType="cdt.managedbuild.target.gnu.cygwin.exe"> <configuration id="cdt.managedbuild.config.gnu.cygwin.exe.debug.2090460160" name="Debug" parent="cdt.managedbuild.config.gnu.cygwin.exe.debug" artifactName="HelloWorld" errorParsers= "org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParse r;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.GASErrorParse r" artifactExtension="exe" cleanCommand="rm -rf"> <toolChain superClass="cdt.managedbuild.toolchain.gnu.cygwin.exe.debug" id="cdt.managedbuild.toolchain.gnu.cygwin.exe.debug.273781351" name="GCC Tool Chain"> <tool superClass="cdt.managedbuild.tool.gnu.c.compiler.cygwin.exe.debug" id="cdt.managedbuild.tool.gnu.c.compiler.cygwin.exe.debug. 1350170342" name="GCC C Compiler"> <option superClass="gnu.c.compiler.option.preprocessor.def.symbols" id="gnu.c.compiler.option.preprocessor.def.symbols. 228974839" valueType="definedSymbols"> <listOptionValue value="DEBUG" builtIn="false" /> </option> </tool> <tool superClass="cdt.managedbuild.tool.gnu.c.linker.cygwin.exe.debug" id="cdt.managedbuild.tool.gnu.c.linker.cygwin.exe.debug. 686918536" name="GCC C Linker" /> <tool superClass="cdt.managedbuild.tool.gnu.assembler.cygwin.exe.debug" id="cdt.managedbuild.tool.gnu.assembler.cygwin.exe.debug. 416825853" name="GCC Assembler" /> </toolChain> </configuration> </project> </ManagedProjectBuildInfo>
You define the majority of your tool-chain integration statically in your XML implementation of the schema. MBS defines a number of attributes in the schema where you can specify a Java class that provides dynamic behavior for your tool-chain. You don't have to implement any of the dynamic behavior, but some may be desirable to your users. For instance, you could implement a Java class that defines the environment variables that must be set up in order to run the tools in your tool-chain. This relieves users from having to set up your tool environment before invoking Eclipse.
To explain the concepts behind creating a tool-chain, let's look at an example.
Say you have a large amount of source code that you wish to code review with your peers. You want to format the code nicely to make it easier for everyone to inspect. You'd also like to put it into one PDF file, both to save on trees and to avoid the confusion created by everyone printing out the code in a different format. With a PDF, all the reviewers can see an identical representation of the artifacts under inspection.
After giving the problem some thought, you realize that since you're running a UNIX-like OS shell (for instance, under Cygwin on Windows) you can use the GNU utility enscript to pretty-print the source files into a PostScript file and then use another GPL'd utility, ps2pdf, to convert the PostScript file into PDF format.
Unfortunately, you know nothing about shell scripting or batch files, but being an expert on using the MBS, you realize that you can create a set of build definitions that will process all of your files, with relatively little effort.
To begin defining the tool-chain, you must have the Eclipse SDK 3.1 and the CDT SDK Feature 3.1.0 installed. Open the Plug-in Development perspective and create a new plug-in:
You have created the plug-in. You will now define your extension to the org.eclipse.cdt.managedbuilder.core.buildDefintions extension point:
The org.eclipse.cdt.managedbuilder.core.buildDefintions extension point uses the object model in Figure 1. The top element in the model is projectType, which serves as a template for the CDT projects that a user will create. CDT uses the information supplied in all projectTypes when populating the New Project dialog box in the Managed Make Project wizards.
To add the ProjectType for the new tool-chain:
To be useful, a project type must contain at least one configuration to build. A configuration consists of a tool-chain that incorporates one or more tools. Typically, a project type contains more than one configuration (for instance, a Debug configuration versus a Release version that uses the same tools but changes some of the optimization and debug options). In this case, however, you need only one configuration, so you'll just create a "default" configuration:
The heart of the build definitions you are creating will be the tool-chain. The tool-chain specifies which tools exist and which types of files they take as input and produce as output. If you have a set of tools whose outputs feed into the inputs of other tools (for instance, a compiler turns .c files into .o files, and the linker takes the .o files as input and creates an executable), then you have a tool-chain. You will define a tool-chain with two tools: A PostScript pretty printer that takes C and C++ source files and turns them into a .ps file, and a PDF converter that takes the .ps file as input and creates a PDF from it.
You will add more information to the tool later. For now, you need to set the inputs and outputs of your tool:
Now it's time to add the PDF converter tool:
At this point, you have all your tools nicely defined, but still lack one crucial piece. The MBS needs to know what utility will actually do the build. In this case, you will use the GNU make utility. Luckily, CDT already includes a GNU makefile generator and a definition for a GNU Make builder that you can simply reuse. If you wished to use some other utility to do the build (nmake, shell scripts, batch files, and the like), you could define your own makefile generator and build definition. For now, you'll just specify that your tool-chain uses the existing GNU Make definitions. If you have access to the CDT source code, see org.eclipse.cdt.managedbuilder.gnu.ui/plugin.xml.
You should now have a working set of build definitions. If you switch to the plugin.xml tab of the manifest editor, you can see the resulting XML description of your plug-in, which should look something like Listing Three. Save your file and then build the workspace.
<?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.0"?> <plugin> <extension id="ddj.example.prettyprinter.toolchain" name="Pretty-Printer" point="org.eclipse.cdt.managedbuilder.core.buildDefinitions"> <projectType id="ddj.example.prettyprinter.toolchain.projectType1" isAbstract="false" name="Pretty-Printer"> <configuration artifactExtension="pdf" cleanCommand="rm -f" description="default configuration" id="ddj.example.prettyprinter.toolchain.configuration1" name="Default"> <toolChain id="ddj.example.prettyprinter.toolchain.toolChain1" isAbstract="false" name="Pretty Printer Toolchain" targetTool="ddj.example.prettyprinter.toolchain.tool2"> <tool command="enscript" commandLinePattern="${command} ${flags} ${output_flag} ${output} ${inputs}" id="ddj.example.prettyprinter.toolchain.tool1" isAbstract="false" name="PostScript PrettyPrinter" natureFilter="both" outputFlag="-o"> <inputType id="ddj.example.prettyprinter.toolchain.inputType1" multipleOfType="true" name="C Sources" primaryInput="true" sourceContentType="org.eclipse.cdt.core.cSource"/> <inputType id="ddj.example.prettyprinter.toolchain.inputType2" multipleOfType="true" name="C++ Sources" primaryInput="true" sourceContentType="org.eclipse.cdt.core.cxxSource"/> <outputType buildVariable="PS_FILE" id="ddj.example.prettyprinter.toolchain.outputType1" name="PostScript Files" outputs="ps" outputNames="${BuildArtifactFileBaseName}.ps" primaryOutput="true"/> <optionCategory id="ddj.example.prettyprinter.toolchain.optionCategory.General" name="General" owner="ddj.example.prettyprinter.toolchain.tool1"/> <option category="ddj.example.prettyprinter.toolchain.optionCategory.General" command="--pretty-print" defaultValue="true" id="ddj.example.prettyprinter.toolchain.option.Pretty" isAbstract="false" name="Pretty-print source code" resourceFilter="project" valueType="boolean"/> <option category="ddj.example.prettyprinter.toolchain.optionCategory.General" command="--color" id="ddj.example.prettyprinter.toolchain.option.Color" isAbstract="false" name="Print in color" resourceFilter="project" defaultValue="true" valueType="boolean"/> </tool> <tool command="ps2pdf" commandLinePattern="${command} ${inputs} ${output}" id="ddj.example.prettyprinter.toolchain.tool2" isAbstract="false" name="PDF Converter" natureFilter="both"> <inputType buildVariable="PS_FILE" id="ddj.example.prettyprinter.toolchain.inputType3" multipleOfType="false" name="PostScript Files" primaryInput="true" sources="ps"/> <outputType id="ddj.example.prettyprinter.toolchain.outputType2" name="PDF Files" outputs="pdf" primaryInputType="ddj.example.prettyprinter.toolchain.inputType3" primaryOutput="true"/> </tool> <builder id="ddj.example.prettyprinter.toolchain.builder1" isAbstract="false" isVariableCaseSensitive="false" name="GNU Make" superClass="cdt.managedbuild.target.gnu.builder"/> </toolChain> </configuration> </projectType> </extension> </plugin>
You should now be able to debug the workspace as an Eclipse application; that is, by using Eclipse to debug itself with your new plug-in included.
If you're in the C/C++ Perspective in Eclipse, use the File>New>Managed Make C++ Project menu item to create a new project. You will see a New Project wizard. Specify a name and location for your project, then click Next. You then see a page that lets you select a project type (Figure 2). In the Project Type drop-down, select the Pretty Printer project type that you created and press Finish.
At this point, if you add C and C++ source files to your project and build your project (CTRL + B), your files should be automatically be processed into a PDF file - assuming your system is set up with make, enscript, and ps2pdf in your path. By using the C/C++ Project view or the Eclipse Navigator view to browse the automatically generated "Default" folder (named after the "Default" configuration you created in your tool-chain), you should be able to see the resulting PDF file (see Figure 3).
If you're using Windows as your OS, you should even be able to open the PDF file directly if you have a PDF viewer installed that is associated with the .pdf file extension (see Figure 4 for the resulting PDF file viewed in Adobe Acrobat Reader).
Now select your project and display its properties. If you select the C/C++ Build item in the left pane, you can set the options that you have defined for the PostScript PrettyPrinter tool. Select the General category and you will see two check boxes for the options that you defined (see Figure 5). Try unselecting one or both of the options and see how the enscript command line is affected by selecting the PostScript PrettyPrinter tool and examining the All options field.
That completes our sample tool-chain definition. For more information on how to create extensions to the MBS, see the CDT Plug-in Developer Guide, Programmer's Guide, Managed Build System Extensibility Document, which is provided with the CDT SDK.
Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.