C H A P T E R  19

Makefile Generation


Introduction

This section describes X-Designer's Makefile generation facilities. X-Designer can create two types of Makefile: simple or with templates. The simple Makefile only contains the build rules for the local .xd file and so is only useful for applications that are contained in a single file. A Makefile with templates can be updated to add files without overwriting your previous work. Unlike most generated files, Makefiles with templates can be edited and regenerated without losing your work.

This section describes the Makefile options available when you generate code for a design. It also provides a short tutorial with step-by-step instructions for creating a Makefile with templates and then updating the Makefile when a second design file is added to the application. Following this tutorial enables you to familiarize yourself with X-Designer's Makefile generation capabilities.


Makefile Generation Options

Pressing the button labelled "Options" beside the makefile text box produces the dialog shown in FIGURE 19-1.

 FIGURE 19-1 Makefile Options Dialog

Makefile Options dialog with default values.

The dialog contains four toggles labelled "New Makefile", "Makefile template" and "Debugging" and a scrolled list. Setting "Debugging" simply adds the "-g" flag to the list of flags to be sent to the compiler so that you can build a version of your application for debugging.

When you generate code in one language and then generate another set of code files in another language, all Makefiles generated afterwards will contain rules for both sets of generated files. Setting the "Current language only" toggle ensures that you are generating a Makefile for the current language only.

New Makefile and Makefile Template Toggles

"New Makefile" and "Makefile Template" relate to the two different types of makefile that you can generate: a simple makefile and a makefile with templates. Which one is generated depends on the way in which the toggles in this dialog are set. The two toggles work in conjunction with one another. There are four ways they can be set:

The List of Makefile Types

The scrolled list in the Makefile Options dialog allows you to generate a Makefile for a specific target platform. For some platforms more than one option is available, allowing for different environments. On Solaris, for example, you can choose compile your application for the 32-bit or the 64-bit architectures. The default for your platform is selected initially. Change this if you wish to generate a Makefile to build your application on another platform or if you wish to use a different compiler from the default. You can, of course, generate any number of different Makefiles to match the environments in which your application will be running.

In some cases, where there is more than one option for a given platform, you can generate a "multi-target" Makefile. This allows you to specify any of the available targets using the one Makefile. For example, the following selection from the Makefile Options dialog:

Solaris 32/64 Multi-target C/C++ (sparc)

generates a Makefile capable of doing the same as all the other Solaris Makefiles available from the Makefile Options dialog. These are:

Solaris 32bit Ansi C/C++
Solaris 64bit Ansi C/C++ (sparc)
Solaris 32bit Workshop4 Compatible C++

Multi-target Makefiles are identified in the Makefile Options dialog by the words "Multi-target". Look at the Makefile itself for the list of command-line options available.

If you wish to build just one version of your application, choose the appropriate Makefile type. If you intend to build your application a number of times--once for each different target on a given platform, you may find the "multi-target" Makefile most useful.

Makefile Generation Notes

There are a few points to bear in mind when generating a makefile:


Creating the Initial Makefile

The first step is to create a design, generate the C code for it and then generate an initial Makefile. It is assumed that you are familiar with the general use of X-Designer.

1. Create a new directory myapp. Make this your current directory and start X-Designer.

2. Build the widget hierarchy shown in FIGURE 19-2

This is a Session Shell with a Form containing a Button.

 FIGURE 19-2 Main Program Widget Hierarchy

Example hierarchy showing Session Shell, Form and Button.

3. Give the PushButton an Activate callback, button_pressed.

Before you generate a Makefile, you must generate the code files that you want to include in it. Generating the code files sets the names for these files in the design file. Until you do this, the Makefile generation feature doesn't know the names of these files and can't add them to the Makefile.

4. Display the Generate dialog and make sure that "C" is the selected language.

The Generate dialog will be primed with filenames based on the save file name or "untitled" if the design has not been saved.

5. Type: myapp.c into the "Code" field and set the "Generate" toggle.

6. Type: myapp.c into the "Main Program" field and set the "Generate" toggle.

If the "code" and "Main Program" filenames are the same, the code file is generated with a main procedure.

7. In the Code Options dialog, set the "Include Header File" toggle.

8. Type: app_stubs.c into the "Stubs" field and set the "Generate" toggle.

9. In the Generate Options dialog, set the "Links" option menu to "None".

Now you can generate a Makefile that compiles and links myapp.c and app_stubs.c:

10. Type: Makefile into the "Makefile" field and set the "Generate" toggle.

11. In the Makefile Options dialog set both "New Makefile" and "Makefile Template" toggles on, as shown in FIGURE 19-3.

The scrolled list on the right of the dialog is described in The List of Makefile Types.

 FIGURE 19-3 Initial Makefile Generation

Makefile Options dialog with the New Makefile and Makefile template toggles set.

12. In the Generate dialog press the "Generate" button.

The generated Makefile contains the required make rules and template lines for further amendment. Ignoring the template lines, the generated Makefile contains the following rules:

XD_C_PROGRAMS=\
		myapp
XD_C_PROGRAM_OBJECTS=\
		myapp.o
XD_C_PROGRAM_SOURCES=\
		myapp.c
XD_C_STUB_OBJECTS=\
		app_stubs.o
XD_C_STUB_SOURCES=\
		app_stubs.c
myapp: myapp.o $(XD_C_OBJECTS) $(XD_C_STUB_OBJECTS)
	$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o myapp myapp.o $(XD_C_OBJECTS) $(XD_C_STUB_OBJECTS) $(MOTIFLIBS) $(LDLIBS)
myapp.o: myapp.c
	$(CC) $(CFLAGS) $(CPPFLAGS) -c myapp.c
app_stubs.o: app_stubs.c
	$(CC) $(CFLAGS) $(CPPFLAGS) -c app_stubs.c

13. Save the current design to myapp.xd.


Updating the Initial Makefile

Once you have generated the initial Makefile, you can update it to reflect additional work. To demonstrate this, use the following instructions to build a popup dialog in another file, generate code for it and then update the Makefile to reflect the new modules.

1. Select "New" from the File menu to start a new design.

2. Build the hierarchy shown in FIGURE 19-4.

 FIGURE 19-4 Secondary Popup Dialog

Screenshot of example hierarchy.[ D ]

3. Name the Shell and MessageBox error_shell and error_box respectively.

4. Give the MessageBox a Cancel callback, cancel_error.

5. Display the Generate dialog and make sure that "C" is the selected language.

6. Type: error.h into the "Externs" field and set the "Generate" toggle.

7. Type: error.c into the "Code" field and set the "Generate" toggle.

8. In the Code Options dialog, set the "Include Header File" toggle and type: error.h into the corresponding field.

9. Type: error_stubs.c into the "Stubs" field and set the "Generate" toggle.

10. Make sure that the "Generate" toggle next to "Main Program" is not set.

11. In the Generate Options dialog, select "None" from the "Links" option menu.

12. Type: Makefile into the "Makefile" field and set the "Generate" toggle.

13. In the Makefile Options dialog turn off the "New Makefile" toggle, leaving the "Makefile Template" toggle set, as shown in FIGURE 19-5.

 FIGURE 19-5 Updating Makefile

Makefile Options dialog with "New Makefile" toggle not set and "Makefile template" toggle set.

14. Press the "Generate" button in the Generate dialog.

The generated Makefile is updated with the new modules:

XD_C_PROGRAMS=\myapp
XD_C_PROGRAM_OBJECTS=\myapp.o
XD_C_PROGRAM_SOURCES=\myapp.c
XD_C_OBJECTS=\error.o
XD_C_SOURCES=\error.c
XD_C_STUB_OBJECTS=\error_stubs.o\app_stubs.o
XD_C_STUB_SOURCES=\error_stubs.c\app_stubs.c
myapp: myapp.o $(XD_C_OBJECTS) $(XD_C_STUB_OBJECTS)$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o myapp\myapp.o $(XD_C_OBJECTS)\$(XD_C_STUB_OBJECTS) $(MOTIFLIBS)\$(LDLIBS)
myapp.o: myapp.c$(CC) $(CFLAGS) $(CPPFLAGS) -c myapp.c
error.o: error.c$(CC) $(CFLAGS) $(CPPFLAGS) -c error.c
app_stubs.o: app_stubs.c$(CC) $(CFLAGS) $(CPPFLAGS) -c app_stubs.c
error_stubs.o: error_stubs.c$(CC) $(CFLAGS) $(CPPFLAGS) -c error_stubs.c

Building the Application

X-Designer has generated the code files for two dialogs, two stub files and a Makefile. All that remains is to fill in the two stubs and build the application.

1. Edit app_stubs.c and make the following changes.

At the end of the generated list of includes, add the following line:

#include <error.h>

Add functionality to the button_pressed callback stub. This callback pops up the error dialog when the button is pressed:

void
button_pressed (Widget w, XtPointer client_data, XtPointer 
									call_data )
{
	...
	if ( error_shell == NULL )
		create_error_shell (XtParent (XtParent (w) ) );
	XtManageChild ( error_box );
}

2. Edit error_stubs.c and make the following changes.

Add functionality to the cancel_error callback. This function pops down the error dialog when the user presses the "Cancel" button:

void
cancel_error (Widget w, XtPointer client_data, XtPointer)
{
	...
	XtUnmanageChild ( error_box );
}

3. Save the current design to error.xd.

4. Open the file myapp.xd in X-Designer.

5. Generate X resources into the file myapp.res.

6. To access these resources do the following:

7. If you are using a C shell enter on the command line:

setenv XENVIRONMENT myapp.res

8. Or, if you are using a Bourne shell or ksh, enter on the command line:

XENVIRONMENT=myapp.res export XENVIRONMENT

9. Set XDROOT to the path of the X-Designer installation directory.

This must be done as the Makefile includes files and libraries relative to the X-Designer installation directory.

10. Build the application. On the command line, type: make

11. To run the application, type: myapp


Editing the Generated Makefile

You can edit and regenerate the Makefile without losing information. You can make the most commonly needed changes by editing the Makefile flags at the beginning of the file. For example, to make the compiler search the ../hdrs directory for header files, append the entry:

-I../hdrs

to the end of the CFLAGS line in the Makefile.

The change to CFLAGS is retained when you regenerate the Makefile with the "New makefile" toggle off. It is only lost if you generate a new Makefile.

Editing Template Lines

A large part of the generated Makefile consists of template lines. Template lines are comments that control the generation of information into the Makefile. Template lines have a #X-Designer: prefix. For example, the following template lines tell X-Designer how to generate the Makefile lines that produce a C object file from a C source file (XDG_C_SOURCE):

#X-Designer:XDG_C_OBJECT: XDG_C_SOURCE
#X-Designer: $(CC) $(CFLAGS) $(CPPFLAGS) -c XDG_C_SOURCE

Each time you update the Makefile to add a file to your application, X-Designer generates a template instance for each relevant template. These instances contain the actual build commands for your application.

Template instances are marked with a "DO NOT EDIT" comment at the beginning and at the end. A typical instance of the template shown above looks like:

#DO NOT EDIT >>>
error.o: error.c
        $(CC) $(CFLAGS) $(CPPFLAGS) -c error.c
#<<< DO NOT EDIT

Template instances should not be edited because your edits may be lost the next time you generate the Makefile. Instead, to change the build commands, edit the corresponding template lines. After you edit a template line, delete any instances of that template line that already exist in the Makefile. The instances are found just after the template line.

For example, to build all C files for debugging, you would:

1. Change the template line:

#X-Designer: $(CC) $(CFLAGS) $(CPPFLAGS) -c XDG_C_SOURCE

to:

#X-Designer: $(CC) $(CFLAGS) $(CPPFLAGS) -g -c XDG_C_SOURCE

2. Remove the instances following the template line.

3. Regenerate the Makefile, with the "New" toggle off, for each design in the application.

This procedure generates new instances using the modified template.

Template Configuration

The original templates are specified by the file pointed to by the following resources:

XDesigner.motifMakeTemplateFile: $XDROOT/make_templates/motif
XDesigner.mmfcMakeTemplateFile: $XDROOT/make_templates/mfc

There are two resources so that you can have different templates customized to pick up the appropriate class libraries. The value for the resource can contain environment variables which will be expanded by /bin/sh.

If X-Designer cannot find the file specified, it will fall back to the template specified in the X-Designer resource file, using the makefileTemplate application resource. To make a change to the template apply globally to all new Makefiles, edit the resource file. For details, see Chapter 25.

X-Designer refers to the template only when you generate a new Makefile. To change templates in an existing Makefile, edit the file by hand as described in the previous section, or delete the file and start over.

Dependency Information

X-Designer does not generate dependency information into the Makefile. The default template includes a "depend" target that can be invoked using the following command:

make depend

This operation invokes the makedepend utility, which scans the existing makefile and appends a standard dependency list. Use man makedepend for more information.


Using Your Own Makefiles

The $XDROOT/make_templates directory contains the template used to generate makefiles. This template contains the include directories and libraries you will need for each system configuration supported. The configuration chosen from the Makefile Options dialog determines which "block" in the template to use. There is always a default configuration for your system so you do not necessarily need to select one from this dialog. See The List of Makefile Types for more details. A typical "block" is shown below:

CODE EXAMPLE 19-1 Typical Generated Makefile Block
##: system Solaris 32bit Ansi C/C++
##: default cpp
#UILFLAGS=-I${MOTIFHOME}/include/uil
#MRMLIBS=-L${MOTIF_LIB_DIR} -lMrm
#CPPFLAGS=-Ddrem=remainder -DS_SUNOS5
#MOTIFHOME=/usr/dt
#MOTIFINCLUDES=-I${MOTIFHOME}/include
#MOTIF_LIB_DIR=${MOTIFHOME}/lib${SYSDIR} -R${MOTIFHOME}/lib${SYSDIR}
#XINCLUDES=${MOTIFINCLUDES} -I/usr/openwin/include -I/usr/openwin/include/X11
#X11_LIB_DIR=/usr/openwin/lib${SYSDIR} -R/usr/openwin/lib${SYSDIR}
#XSYSLIBS=-L${X11_LIB_DIR} -lXt -lX11 -lXext -lnsl -lsocket -lgen
#MOTIFLIB=-L${MOTIF_LIB_DIR} -lXm
#CC=cc
#CCC=CC
#ABI2CFLAGS=
#ABI2CCFLAGS=-compat=5
#ABI2LDFLAGS=
#ABI2ABIDIR=/ansi32
#ABI2SYSDIR=
#ABICFLAGS=${ABI2CFLAGS}
#ABICCFLAGS=${ABI2CCFLAGS}
#ABILDFLAGS=${ABI2LDFLAGS}
#SYSDIR=
#ABIDIR=/ansi32
##: endfs

XINCLUDES and XLIBS specify the extensions to the included directory and library path respectively.