C++ (with Understand)#

The Lattix Understand for C++ module reads the .udb files from Scientific Tools Understand for C++. Understand for C++ is an interactive development environment (IDE) designed to help maintain and understand large amounts of legacy or newly created C and C++ source code. It works well even if the source code does not compile or if the build environment is not setup.

You can obtain an evaluation version of Understand for C++ from https://licensing.scitools.com/download

Version Compatibility#

Understand API and licensing changed significantly in build b921.

Lattix Architect version 10.9+#

Lattix Architect 10.9 supports Understand 5.0 by default. To run Architect 10.9+ with older versions of Understand, you have to switch the DLL in the install directory.

Understand build 932+

Architect is setup to work with these builds by default. Note that you must set the environment variable STI_HOME to the directory where you installed Understand, typically c:\Program Files\Scitools. To avoid doing this every time, we suggest that you set this variable for the entire system so that it is set prior to running Lattix Architect.

Understand builds 919-

To use Architect with builds older than and including builds 919, follow these steps prior to starting Architect:

  • Rename the jniUnderstand.dll to jniUnderstand_old.dll. These files are located in the bin/win32 or bin/win64 directories of your Lattix installation.

  • Rename the file jniUnderstand_b919-.dll to jniUnderstand.dll.

  • Start Lattix Architect after renaming the files.

Lattix Architect version 10.8.1#

Architect version 10.8.1 now comes with 2 DLLs to support the old and the new scheme. By default, Architect 10.8.1 supports builds prior to build 921.

To use Architect with builds later than 921, follow these steps prior to starting Architect:

  • Rename the jniUnderstand.dll to jniUnderstand_old.dll

  • Rename the file jniUnderstand_b921+.dll to jniUnderstand.dll.

  • Start Lattix Architect after renaming the files.

If using Understand build 932 or later, the Understand library may be unable to find the QT Package. Here is how to fix:

  • Environment variable STI_HOME should be set to the directory where you installed Understand, typically c:\Program Files\Scitools) on Windows. Setting STI_HOME should allow Understand to find the QT Package library.

    Note: We suggest that you set this variable for the entire system so that it is set prior to running Lattix Architect. Otherwise, you will have to set the variable every time in a command window prior to running Architect from that window.

  • If Understand is still unable to find QT Package, set QT_QPA_PLATFORM_PLUGIN_PATH environment variable.

    On Windows 64bit:
    set QT_QPA_PLATFORM_PLUGIN_PATH=%STI_HOME%\bin\pc-win64\Plugins\platforms

    On Linux 64bit

    export QT_QPA_PLATFORM_PLUGIN_PATH=$STI_HOME/bin/linux64/Plugins/platforms

Notes on version compatibility#

  • The instructions above are for Windows. For Linux and Mac versions, you will have to change the instructions slightly to correspond to the platform.

  • Understand ‘udb’ format does change. This can lead to a version mismatch between the udb file and the Understand API library. For instance, an older Understand API library may not work with a newer version of ‘udb’. Lattix uses this API library which is contained within the Understand installation. This means that the ‘udb’ file must be written by the version of Understand that is installed on the system that Lattix runs on. If that is not the case, you must first load and then save the ‘udb’ using the version of Understand on your desktop. This is the most common issue that leads to questions about compatibility..

  • Understand makes new builds available regularly, typically every week. Lattix also makes new builds available regularly, typically once a month. It’s not possible for us to test every build of Lattix with every build of Understand (and there is certainly no way to test against future builds). When we say we have tested a certain version of Lattix against a certain version of Understand, we mean that we have tested at least one build of Lattix against one build of Understand for each of those versions.

Configure Architect to Work With Understand for C++#

The Understand module uses a library from Scientific Tools to read Understand database files (*.udb). Installing Understand 2.0 installs the library and alters the system PATH environment variable to include the Understand installation.

Windows: The Understand library is called udb_api.dll and is typically found in the C:\Program Files\SciTools\bin\pc-win32 directory. If, after installing Understand, Architect reports that the API library is missing, try logging out and logging back into your Windows session.

  1. Make sure the environment variable STI_HOME points to the installation directory for the Understand application. The Lattix scripts use this variable to find the udb_api.dll

  2. Please ensure that path contains the directory C:\Program Files\SciTools\bin\pc-win64 or C:\Program Files\SciTools\bin\pc-win32.

  3. Note that 64-bit Lattix will work with 64-bit Understand and the 32-bit Lattix will work with the 32-bit version Understand. You cannot use 64-bit version ofLattix with 32-bit version of Understand or vice versa.

Linux: The Understand library is called libudb_api.so and is found in the bin/pc-elf directory of your Understand installation. You can specify the location of your Understand installation by setting STI_HOME environment variable to point to the top of your Understand installation. Alternatively, the shell scripts start up Architect (i.e. lattixarchitect.sh) will attempt to locate your Understand installation. The scripts cache the results of this search, so the search is conducted only once.

Mac OSX: Lattix Architect looks for the Understand installation in /Applications/scitools. If you installed Understand in a non-standard place, simply create a symbol link from /Applications/scitools to your installation of Understand :

ln -s /your/understand/path /Applications/scitools

Please note older versions of Understand used a different file organization. As a result, with older versions of Understand (builds prior to Build 858), you may need to edit your Lattix installation configuration. Edit the file “/Applications/Lattix Architect 10.5.app/Contents/Info.plist”. Replace all occurrences of the string “/Applications/Understand.app/Contents/MacOS/C” and “/Applications/Understand.app/Contents/MacOS” with the string “/Applications/scitools/bin/macosx”.

Create a Project from a UDB File#

Once you have generated your UDB file, start LDM.

  • Select New Project from the File menu in LDM.

  • Select C/C++ (Understand) from the Module Type drop down

  • Navigate and select the UDB file in the file tree

  • Click on Add File (or double click) to add the UDB file to the project.

  • Click on Create Project

image7

New Project

The Understand module can read .udc files (from Understand 1.4) and .udb files (from Understand 2.0). The UDC Module also supports .ldi files, which allow you to augment the Understand data for elements in your LDM.

Atom Types#

The DSM is composed of atoms and dependencies. Here are the kinds of atoms generated by the UDC module:

  • Header File is typically a .H file. Header files usually contain macros, class definitions and function prototypes.

  • Source File is typically a .C, .CPP or .CXX file. Source files contain executable code.

  • Class is a C++ class, struct, union, enum or typedef.

  • Interface is a C++ class with only pure virtual methods.

  • Data is either a global variable, a class member or an enum value

  • Method is either a global function or a member function

  • Macro is a lexical macro (i.e. #define)

Dependency Kinds#

Dependency kinds can be used to filter the dependencies visible in the DSM. The UDC module supports these dependency kinds:

  • Include dependencies are generated when source file uses #include to add an include file to the compilation stream.

  • Data is a reference to a variable or member. It has three sub-kinds:

    • Global is a reference to a global variable

    • Member is a reference to a class or struct member.

    • Enum is a reference to an enum member

  • Class is a reference to a class, struct, union, enum or typedef. It has these sub-kinds:

    • Reference is the catch-all sub-kind.

    • Inherit indicates that the source is a sub-class of the target/provider.

    • Friend indicates that the source has a friend class of the target/provider.

    • Weak Type indicates a reference that does not require full knowledge of the target/provider class. For example:
      class Foo;
         ...
      void myFunc(Foo *x) {
         ...
      }
      

      The “Foo *” in the function signature of myFunc generates a dependency myFunc uses Foo, Weak Type dependency kind.

  • Method is a dependency on a method. In has these sub-kinds:

    • Override is a dependency between a method and the base class method it overrides.

    • Invoke is a dependency that indicates a method calls a method.

  • Declaration is a dependency between a declaration and an implementation / instantiation. Typically, this is some sort of forward declaration. In the example above, the “class Foo;” line would generate a declaration dependency between the file containing the “class Foo;” and the file that contains the definition of class Foo. The UDC module also generates Declaration dependencies between function forward declarations and the implementations.

  • Macro is a dependency on a lexical macro (#define). It has these sub-kinds:

    • Use Macro is the catch-all for macro references

    • Configuration Macro is a reference to a macro that is used to control the configuration of a header file. For example:

    myfile.cpp:
    
    #define WINDOWS_LEAN_AND_MEAN
    #include <windows.h>
       ...
    windows.h:
    #ifndef WINDOWS_LEAN_AND_MEAN
        : do something
    #endif
    

    Normally, this construct would show a dependency of windows.h using mpfile.cpp. As a result, this dependency actually detracts from architectural analysis. By default, configuration Macro dependency kinds are filtered.

  • in Macro Definition is a reference from one macro to another:

#define N1 10
#define N2 (2 * N1)
N2 uses N1, “in Macro Definition” dependency kind.

Options#

There are several configuration options for the Understand module. You can configure these options in the Project Properties dialog box accessible by selecting Project Properties from the Project menu.

Enable Line Number Processing adds source file line number information for dependencies and member objects. LDM uses this information to navigate to the definitions of DSM elements and source of a dependency in the source code using Understand.

Exclude non-include header file dependencies removes all dependencies from header files that are not caused by a #include preprocessor command.

Fold Unnamed Types into Typedefs: Constructs such as these create unnamed types:

typedef struct {
    int x;
} MYSTRUCT;

The Understand for C++ module contains an option for “folding” the unnamed structure into the typedef that follow. This option is enabled by default. References to the structure member x will refer to MYSTRUCT.x in the LDM.

Filter duplicate global elements removes global function and data entities whose names are not unique. This can sometimes be helpful in removing inaccurate dependencies caused by defining functions or global variables of the same name in multiple compilation contexts and then creating a single UDB file that spans both contexts.

Visibility Filter uses lexical visibility to filter erroneous references sometimes generated by Understand when the Understand project spans multiple compilation units. A target (also known as a provider) is lexically visible from a source (also known as a consumer) if the source and target are in the same file or the file containing the source #include’s a file the contains a definition for the target.

Use visibility to resolve references to multiply defined symbols - When an Understand project spans multiple compilation Units it sometimes generates erroneous references to multiply defined symbols. Using lexical visibility can sometimes remap these erroneous references.

Ignore include references to non-unique header files - When an Understand project spans multiple compilations Units, there can be multiple occurrences of a header file with the same name. Sometimes Understand generates an erroneous references to the wrong one of these files.

Scan namespace for duplicates - With this option enabled, the UDC module tracks duplicate symbol names and filters or corrects references generated to them.

Skip symbols matching these patterns filters out symbols whose names match a user specified list of regular expressions. The match is case sensitive.

Skip these files filters out files by base file name. For example, to remove all stdafx.h files from your model, add stdafx.h to the list.

Enable File Filtering must be enabled to filter the files specified in Skip these files.

Project Options and Large Understand Projects

You can use the project options to reduce the amount of memory / processing time that LDM requires to process a large Understand project. The default configuration of the options is designed to improve the fidelity of the LDM, particularly with respect to Understand projects that span multiple compilation units.

If you are running out of memory building an LDM from a UDC file, you might try:

  • disabling Visibility Filter and Use visibility…

  • disabling Scan namespace for duplicates

Mapping Dependencies to Code#

You can navigate to the dependency in Understand directly from the DSM or CAD.

After you’ve loaded your model into Architect, you will partition it to determine the architectural layering of your system. Consider Apache:

image8

This image shows a proposed architectural layering. The highlighted “12” is a set of dependencies that violate the layering. The usage pane looks like this:

image9

This image shows the 12 dependencies that violate the layering in the DSM. If you select http_core.c, the Uses pane shows that something in protocol.c is using a global variable defined in http_core.c:

image10

Now the question is, “what’s in protocol.c that uses a global in http_core.c”. To investigate, we’ll member level expand protocol.c and http_core.c.

  • Right mouse on http_core.c and select Expand Members

  • Right mouse on http_protocol.c and select Expand Members

The member information is displayed and we can ap_read_request, defined in protocol.c, uses ap_http_input_filter_handle, defined in http_core.c.

Understand Integration

We can research this further using Understand.

  • Load up the UDB file in Understand

  • Switch back to Artchitect

  • right mouse on the dependency (ap_http_input_filter_handle in the example) and select View Source from the menu.

If this is the first time that you have used the view source command, Architect will ask you to select the editor:

image11

Artchitect attempts to locate Understand. On Windows, if you’ve installed Understand in the default place, Artchitect will build a command line that facilitates integration with Understand.

  • Select understand-cpp and press OK

Understand will display the line in protocol.c that references ap_http_input_filter_handle.

  • Right mouse on ap_http_input_filter_handle in the Understand editor window and select View Information from the context menu.

Understand’s information panel diplays information about ap_http_input_filter_handle:

image12

This shows that ap_http_input_filter_handle is defined in http_core.c and has a Use reference in protocol.c.

Large Model Strategy

In the event that a model is too big to expand its members, you can still use the View Source to point Understand at the code where a reference occurs. If we had used View Source on http_etag.c, we could see the point in the code that caused that reference, as long as the Enable Line Number Processing option was enabled.

Integrating with LDC#

LDC is Lattix command line program which can be run as part of the build process for continuous monitoring of the architecture. LDC takes the UDB file generated by Understand as input. Understand also provides a command line tool for creating and updating the udc file. This tool is called und in Understand. You can instrument your build so that you first run und and then run LDC. und is documented in the Understand User Guide and Reference Manual. Help can also be obtained by running und with the -help switch. LDC is documented in the User Manual.

Here in an example sequence of commands for updating a project:

set path="C:\Program Files\Lattix5.0.6\bin";%PATH%
set path="C:\Program Files\SciTools\bin\pc-win32";%PATH%
und -db httpd-2210.udb analyze -all
ldcupdate httpd-2210.ldz -deltaTags
ldcreport  httpd-2210.ldz -impact -source:UpdateDelta -closure -report:html

The und line updates the Understand dependency database httpd-2210.udb by re-parsing the source files that were used to create the project.

The ldcupdate line updates the Lattix project by re-parsing the dependency information in httpd2210.udb. It also marks everything that is new or changed with the tag “UpdateDelta”.

The ldcreport then generates an impact report on all the elements that are tagged “UpdateDelta”.

Example - Apache Server#

This example will walk you through the process of creating a dependency model for two different versions of the apache server starting from the source code. This consists of three steps:

  1. Download the source code.

  2. Generate the UDB database using Understand

  3. Create a dependency model using Lattix Architect

Note that you can skip the first two steps if you are already familiar with the process of creating a UDB file. If that is the case then you can simply download the udc file that we have already created.

Download the source code for Apache Server 2.0.55#

Download source code for Apache Server 2.0.55 from the following url:

http://archive.apache.org/dist/httpd/

Unzip and extract the files. The files will be extracted into the directory httpd-2.0.55 which will be a sub-directory of the directory where you choose to extract the files. This is the source for Apache Server version 2.0.55 for windows. It is 230K lines of code distributed in 340 source files and 165 header files. It does not contain the standard include files which are part of the compiler.

Generate the UDB file from Understand#

Follow these steps to generate the UDB file for Apache Server 2.0.55:

  1. Run Understand

  2. Select File->New Project and specify the name httpd2055 in the New Project Dialog and click on Open.

  3. A Project Configuration Dialog will open. Specify the htpd-2.0.55 directory in the Directory field. Now click on Add.

  4. Click on Save to start up the parsing. Since the source code does not include standard header files, you will see the Missing Include File Dialog. Select stop warning about missing include files and click on Okay.

Load the UDB file into Lattix#

Follow these steps to generate the UDB file for Apache Server 2.0.55.

  1. Start Lattix Architect and bring up the New Project Dialog

  2. Select Module Type to Understand for C++

  3. In Input Sources, select the UDB file, httpd2055.udb, that you just created using Understand for C++ and click on Add.

  4. Now click on Create Project and a progress bar will appear indicating that the file is being loaded in. The file should load within 10-20 seconds.

Using Lattix Architect#

This section presents a cursory outline of the some the analysis capabilities. For a more detailed reading, we suggest that you read Lattix white papers and the tutorial.

image13
Initial DSM

Now partition the DSM and you will get a sense of the structure. You will also notice a few dependencies that appear to violate the architectural intent.

image14
Partitioned DSM

The re-ordered DSM moves srclib to the bottom. srclib contains the portable runtime and other utilities and provides services to the rest of the system.

You can click on an individual cell and see the dependencies associated with that cell in the usage pane. Notice that even though the Apache server is modularized to allow new modules to be added to it, the server is actually coupled to the httpd module.

Exploring Member Level#

The initial DSM has files as the leaf nodes. You can also explore a file down to its methods and data members. Simply select a partition, right click and choose “Mark Member Level Dependencies”. If you want to see member level dependencies for the entire project, simply select $root and expand to member level.

image15
Files are Expanded down to their Methods and Data members

Other Functionality#

Lattix provides a variety of useful functionality to manage the architecture. Some of these include:

Filtering Dependencies: Lattix Architect classifies each dependency based on their dependency kinds. You can select View->Filter Dependencies to bring the Filter Dependencies Dialog. You can then specify what kinds of dependencies you want to display. For instance, if you wanted to look at method call dependencies, you can do that easily. You can also filter for source/consumer and target/provider of dependencies. Thus, if you wanted to see the dependencies that include files have on include files you can do that easily as well.

Conceptual Architecture: You can create a conceptual architecture that displays the decomposition in a box-in-a-box diagram. The layout of the boxes is used to represent the layering and independent components.

Reporting: A variety of reports can be generated using Tools->Reports. Many output formats are supported including xml, html, xls, text and csv.

Conformance Checking: You can specify architectural rules and then verify them at build time using a command line utility (LDC). You can also use LDC to automate reporting and publishing of the results to an intra-net web site.

View Source: You can view source for any of the subsystems directly from Lattix Architect. On Windows, Lattix will invoke the notepad program to display the source. However, you can configure Lattix Architect to invoke Understand for C++ directly from the View Source menu.