Programming Guide


Building Sample Parts

       

OpenDoc provides a set of samples that you can build. On the OS/2 and Windows platforms, the samples are built with nmake. On the AIX platform, the samples are built with /usr/bin/make.

The simplified, straightforward makefiles include Platform.mak. This is a platform specific makefile that contains the rules that builds the parts on each platform.

The part developer's makefile for the OS/2, Windows NT, and Windows 95 platforms are the same however, a different makefile exists for the AIX platform.

As a common format, we chose the unix approach to full path delineation and we chose to use a build tool that was already available to every part developer. The nmake tool comes with both the VisualAge and Visual C++ compilers. The /usr/bin/make tool is native on the AIX operating system. Anyone who has the correct compiler installed on their platform already has the correct build tool available with the current nmake tool and /usr/bin/make tool approach.

The Build Environment

   

Here are some guidelines to follow in order to use the samples build environment:

For all three platforms, if you plan to build packages, a 32-bit compression tool must be installed. You can use Info-ZIP. It is freely available from Compuserve in the IBMPRO forum and by anonymous ftp from the Internet site ftp.uu.net:/pub/archiving.zip.

The build process does a generic compile and link. It does this so that the decision to build either optimized or debug is not hard-coded in the makefiles. The build process uses the following environment variables as part of the compile and link process. This allows the developer to change from building a debug build to an optimized build without having to edit any makefiles. The following shows settings for builds on the various platforms.  

The OS/2 Platform

VisualAge Compiler options are as follows:

The Windows platform

VisualAge Compiler options are as follows:

Visual C++ Compiler options are as follows:

The AIX platform

xlC Compiler options are as follows:

Part Developer's Makefile

 

Each part developer's makefile is divided into 3 sections:

Macro Definitions

   

The following are macros that can be used in a part developer's makefile:  

ExtraSOMCompileOptions

This macro lists any extra options passed to all calls of the SOMObjects compiler for this part.  

ExtraCompileOptions

This macro lists extra options passed to all calls of the compiler for this part. If you want your code to be compilable on different compilers be very careful what you add. Flags mean different things to different compilers.  

ExtraLinkOptions

This macro lists any extra options to be passed to all calls of the linker for this part. If you want your code to be linkable by different compilers be very careful what you add. Flags mean different things to different compilers.  

Subdirs

This macro lists all subdirectories to be visited by the build process.  

IdlTargets

This macro lists the idls in the local directory that needs to be shared with other part developers. The idls in this macro are copied to ODSRC/include and will have .xh headers generated.  

HdrTargets

This macro lists the C++ headers in the local directory that needs to be shared with other part developers. All the headers in this macro are copied to ODSRC/include.  

RcTargets

On platforms that have resources (OS/2 and Windows) this macro lists the resource script files that are input to the resource compiler.  

MsgTargets

MsgTargets are language-specific targets that need to be built. They include message catalogs and help files because you may have a separate message catalog or help file for each language your part supports.  

LibTargets

This is one of the few macros that requires a full path length. It specifies the full path length of every export library to be built.  

DllTargets

This is one of the few macros that requires full path length. It specifies the full path length of every dll, or shared library, to be built.  

RegeditTarget

This macro is only for the Windows platform. Some dlls may need to be registered with the Registry Editor. If so, specifying the registry input file in this target will mean the regedit tool is called when the ForceRegistry target is used.

You do not need to use the RegeditTarget macro if you are building an OpenDoc part (that is, you have the series of Reg* and Files* macros set), and if you have an associated typelib (you have the Ctypelib* macros set). Your part will be registered through the generated typelib when the ForceRegistry target is used.

The following macros build a typelib for the Windows platform only. Note that they must be used concurrently.  

CtypelibIDL

This macro specifies the idl that must be registered in the SOMIR environment variable before the typelib can be built.  

CtypelibDir

This macro specifies the directory where you are building the typelib.  

CtypelibCmdLineArgsFile

This macro specifies the file that contains the rest of the command line arguments for the ctypelib command. The -t flag is set using the CtypelibDir macro since you cannot specify a relative path in a command line arguments file. The rest of the arguments to ctypelib are in this file.

Macro Definitions for Reg* and Files*  

Reg* and Files* macros are used to build a table of contents and an installable package for an OpenDoc part. None of these macros take a full path length as Platform.mak knows where to look for them. See "Defining the Table of Content Entries for Your Part Handler" for details.

The Include of Platform.mak

 

The Platform.mak include brings in the main build logic. Platform.mak on AIX and OS/2 has the logic used to build the samples. Platform.mak on Windows determines whether to include Platform.nt or Platform.w95 (the shell script language works differently on Windows NT and Windows 95). For simplicity's sake, we will only refer to Platform.mak, even though the logic is in Platform.nt and Platform.w95 on Windows NT and Windows 95 respectively.

The problem with including Platform.mak after the macros is if you want to use platform-specific references before the include of Platform.mak. The Platform macro is set in Platform.mak, so you can not reference it before it is set. It is recommended that you delineate macros you want set for the OS/2 platform with:

  !IFDEF OS2_SHELL
  !ENDIF
Delineate macros you want set on the Windows NT platform with:
  !IF "$(OS)"=="Windows_NT"
  !ENDIF
The Windows 95 platform can be referenced by:
  !IFNDEF OS2_SHELL
  !IF "$(OS)"!="Windows_NT"
  !ENDIF
  !ENDIF

Simplified Inference Rules

     

At the bottom of each part developer's makefile are the simplified inference rules. Typically, they consist of:

The first thing you may notice about the inference rules is the use of some generic macros. For example, $(Obj), $(Def), $(Exp), or $(LibSuffix). These macros help promote usability across different platforms. An object file has an extension of .obj on the Windows 95 platform, but has an extension of .o on the AIX platform.

The $(Def) and $(Exp) macros may be confusing because a file with an extension of .def and a file with an extension of .exp mean different things on different platforms.

  $(Def) = the input file to building the export library (.lib or .a)
  $(Exp) = the input file to building the shared library (.dll)
On the OS/2 and AIX platforms, the $(Def) and the $(Exp) files are the same file. On those platforms the macros resolve to the same value. On the Windows platform, they are different files and the macros resolve to different values. We used $(LibSuffix) instead of $(Lib) because the Windows NT and Windows 95 platforms have a LIB environment variable therefore, a $(Lib) macro would get confused about when it is referring to the environment variable verses the macro. Also, on the AIX platform, there is a corresponding $(LibPrefix) being that libraries there begin with 'lib'.

A complete list of the macros that can be used to promote portability between platforms can be found in the Platform.mak file.

The inference rules in the part developer's makefile specify what are the sources needed to build the target. If the .xih header is needed, it must be placed in these inference rules so it can be built. For example:

  iodlink.$(Obj) : iodlink.xih
Files with an extension of .cpp are optional when building $(Obj)s, because the rule that builds the $(Obj)s forces the relationship with the .cpp. But all headers should be mentioned so the $(Obj) will re-build if a header is touched.

The macros set in this section, typically *ObjList and *LibList macros, are mostly for readability. They also provide a single place where the object files and libraries are listed. That helps if a list has to be used twice, such as *ObjList, which is used in building the export library as well as the shared library.

The build rules for each target are defined in Platform.mak. These rules are implemented through recursion. For example, to build an export library, the part developer's makefile uses $(BuildLib) as the rule. $(BuildLib) is a macro defined in Platform.mak that calls the BuildLibRule. Therefore, Platform.mak has some common rules and a set of macros so the part developers can easily call them in their specific inference rules. For more information about the common set of rules and macros, see "Remaining Rules".

Platform.mak

 

Because Platform.mak is different on every platform, we cannot provide specific rules and approaches however, there are some general concepts common to all Platform.mak files.

They all use shell script logic. Because neither nmake nor /usr/bin/make provide any kind of looping capability, the Platform.mak files must rely on the shell script logic available on each platform. But in both nmake and /usr/bin/make, the build tool does not run each rule as a separate script. It runs each line as a separate script. Therefore, each loop can only be one line long. This is why, on the AIX platform, you see long shell script sections held together with backslashes. You can see the same thing on the Windows NT platform, where each FOR loop can only be one line long.

The following is the layout of each Platform.mak file:

Considering the smallest Platform.mak file is over 700 lines long, a lot occurs in each of these sections.

Environment Variable Macros

 

A build environment needs to be able to run on a variety of different machines. Each machine probably has a unique set of environment variables. Some environment variables are essential for a command to run correctly. For example, the SOMObjects compiler looks at the .idl in SMINCLUDE before it looks at the .idl specified through the -I flags. Therefore, the setting of SMINCLUDE greatly affects the output of the SOMObjects compiler. The build environment needs to control certain environment variables during the build in order to build correctly. It does this by setting specific critical environment variables before a command was run, and by clearing the setting afterwards. This does not affect the environment on your machine, being that the build is run in a separate shell.

Whenever an environment variable has to be modified to ensure subsequent commands will run correctly, it is displayed to the developer. If the developer wonders why the SOMObjects compiler runs correctly in the build, but not from the command line, the environment variables that were modified to ensure correct execution are visible in the build.

The macros that are used to reset the environment variables are at the top of Platform.mak. This makes it easy to see what environment variables are used during the build and you can change them if necessary.

A word of caution about nmake on the OS/2 platform. Sometimes nmake cannot correctly parse a 'set <environment variable>=<null>' statement. For example:

  set SMINCLUDE=
Sometimes it will work but other times it will not handle the null correctly in nmake's local copy of the environment variables. For the time being, do not set an environment variable to null on OS/2.

General Use Macros

   

General use macros are self explanatory. They can be a little confusing on the Windows platform, where there are two sets, one for the VisualAge compiler, and one for the Visual C++ compiler.

Default Target and Its Corresponding Rules

 

The default target is what is built if no target is specified. In Platform.mak, the default target is 'Idls Hdrs Libs Dlls'. This means there are four passes through the build tree, one for each of these settings.

Remaining Rules

   

After the default target, is the section that contains the default and miscellaneous build rules. There are some straight-forward rules, such as how to build an .xh file from an .idl file but there are also some other interesting rules.  

ForceRegistry

There are build actions that you do not want to have happen on a regular basis, therefore they are not part of the default target. ForceRegistry is one of them. Ordinarily, the default target handles the case of registering your part when your .idl is newer than the opendoc.ir file. For a single part developer, this is the correct time to register your part but in a build environment the logic may not work as well. If you are doing a complete rebuild, using a new opendoc.ir, the first .idl that the build encounters will get registered correctly with the default target rule. This initial registry updates the opendoc.ir file and it is now newer than subsequent .idl files encountered in the build. Keep in mind that the default rule only allowed the first .idl encountered to be registered.

If you want to force the registration of every RegIDL in the build tree, execute the following after the regular build:

  nmake ForceRegistrys      (on Windows or OS/2 platforms)
or
  /usr/bin/make ForceRegistrys    (on AIX platforms)

On the Windows platform, running ForceRegistry runs scriptrg for every OpenDoc part that has a typelib, and it runs regedit if the RegeditTarget macro indicates you have input files for the RegistryEditor. These actions were put in the ForceRegistry rule because a parts developer does not want to have them happen every time they rebuild their dll.

ForceRegistrys (with an 's') does this for the current directory, and the subdirectories listed in the Subdirs macro.

Pkg
 

Opendoc parts can be built into installable packages that other OpenDoc developers can install. For more information on packages and how to install them see "Installation of OpenDoc Software".

The Pkg target allows the developer to build an OpenDoc installable package. It creates the table of contents for the package (the .odt file), as well as the parts.lst file, before building the package. The build environment used the Reg* and Files* macros to build these files and the package. By using macros to build the table of contents and the package, the build ensures that everything exists that you believe should be in your package, and only the files mentioned in the macros get placed in the package. A package cannot be built unless everything exists and extraneous files are not placed in the package.

On the OS/2 and Windows platforms, the package is built using 32-bit zip tools.

On the AIX platform, the package is built using tar and compress, which are native to the operating system.

Pkgs (with an 's') builds packages for the current directory, and the subdirectories listed in the Subdirs macro.

BuildCopy
 

BuildCopy is not a rule, it is a macro that recursively calls the BuildCopyRule. However, BuildCopy is used as the rule in many of the part developers makefile to copy files. For example:

  $(ODSRC)/lib/iodbasec.$(Def) :  iodbasec.$(Def)
      @$(BuildCopy)

This copies iodbasec.$(Def) to $(ODSRC)/lib/iodbasec.$(Def) on all platforms.

BuildDef
 

BuildDef is not a rule, it is a macro that recursively calls the BuildDefRule. However, BuildDef is used as the rule in the part developers makefile to build the $(Def) file for C++ export libraries.

Note:

AIX developers, a $(Def) is an .exp file.

This rule should not be used to build the $(Def) for SOMObjects export libraries. The $(Def) files for SOMObjects export libraries only need three symbols per class, and BuildDef builds the $(Def) from the symbols in the object files. The $(Def) file for C++ export libraries usually has to be remade every time you build an export library because any change to the API changes the $(Def) file for C++. With SOMObjects, once you build the $(Def) file, the only reason you would need to change it is if you added or deleted a SOMObjects class in your dll. Most SOMObjects developers create their $(Def) once, and use the BuildCopy rule to copy it to the correct location.

The usual way a parts developer creates their $(Def) file for SOMObjects export libraries is to use the SOMObjects compiler. Instructions for how to do this are in the SOMObjects Base Toolkit User's Guide. On the Windows platform, the .def file created by the SOMObjects compiler only works for the VisualAge compiler. If you are working on the Windows platform and you are using the Visual C++ compiler, you may want to take these steps:

  1. Use the SOMObjects compiler to create your .def file.
  2. Remove the underscore "_" in front of each export.
  3. Remove the "@8" at the end of each NewClass.
  4. Rename or copy the new .def file to an .mdf file.
This should change your .def file into one that will work with the Visual C++ compiler.

Because some parts on the Windows platform needed to be able to compile with both the VisualAge and the Visual C++ compilers, the build environment set the standard that .def files were used as input to the VisualAge compiler, and .mdf files were input to the Visual C++ compiler. The BuildLib rule discussed in the next section uses these conventions to build an export library.

Because of this manual editing that needs to be done for the .def file on the Windows platform for the Visual C++ compiler, Platform.mak has no rule to automate the creation of the $(Def) from the .idl.

BuildLib
 

BuildLib is not a rule, it is a macro that recursively calls the BuildLibRule. BuildLib is used as the rule in many of the part developers makefile to build the export library.

The sources to build the export library always include the list of object files. If you are using the VisualAge compiler, it also includes the $(Def) file. If you are using the Visual C++ compiler, it cannot include the $(Def) file. These are restrictions of the two compilers. If you are working on the Windows platform, and you want your code to be able to be compiled with both compilers, the following is an example:

      $(ODSRC)/lib/iodbasec.$(LibSuffix) : \
  !IFDEF CPPMAIN
          $(ODSRC)/lib/iodbasec.$(Def) \
  !ENDIF
          $(bcpartObjList)
          @$(BuildLib)

BuildDll
 

BuildDll is not a rule, it is a macro that recursively calls the BuildDllRule. However, BuildDll is used as the rule in many of the part developers makefile to build the shared library.

BuildDllWithRes
 

BuildDllWithRes is not a rule, it is a macro that allows the developer to recursively call the BuildDllRule if the developer is building a Dll with a resource file.

Resource files only exist on the OS/2 and Windows platforms. They do not exist on the AIX platform. The rule exists on the AIX platform to aid in portability, but it does nothing different than the BuildDll macro would do.

On the platforms that support resource files, the developer must pass the resource file to the BuildDllRule in the RecFile macro. For example:

  $(ODSRC)/dll/iodbasec.dll :  $(ODSRC)/lib/iodbasec.$(Exp) \
      $(bcpartLibList) \
      $(bcpartObjList)
      @$(BuildDllWithRes) "RecFile=colordlg.res" BuildDllRule
The resource file should have been compiled prior to the building of the Dll, which means the RcTargets macro should have been used to create the .res file from the .rc file.

Clean Rules

   

There are times when the developer wants to clean the build tree, removing everything created by the build. The clean rules remove the generated files so the developer can build in a "clean" tree.

The easiest clean rule to use is Cleans. This rule removes the generated files in the current directory and in all subdirectories listed in the Subdirs macro.

In addition to the overall Cleans rule, there are rules to clean the files generated by each main rule. These rules are:

The Cleans rule calls all of these specific clean rules.


[ Top | Previous | Next | Contents | Index | Documentation Homepage ]