[prev] [up] [next]

How to Create & Add Binary Classes/Libraries

Notice:
Most of this document has become obsolete by the availability if the package-builder. This tools allows for a very convenient build-process for both standalone executables and binary class libraries. It will generate all of the files which are described below automatically.

Contents

Introduction

The most interesting feature distinguishing Smalltalk/X from other Smalltalk implementations is the ability to create native object files and (possibly shared) libraries from Smalltalk classes. Thus, you can create and deploy pure object files, which do not contain bytecode, and can therefore not be decompiled (or at least: this becomes a non-trivial task).

These class libraries may contain embedded C-code; either for performance reasons or to interface to other C-libraries.

This document will give you information and a step-by-step guide on how to compile your classes to machine code, how to create & package class libraries for distribution and how to include such a binary class library in your system.

Notice, that beside speed advantage and the ability to include inline C code, the semantic of binary compiled code is equivalent to that of interpreted bytecode. All language features (such as context handling, block handling, stack unwinding and exception handling) are available and perform transparent whether methods are compiled statically or interpreted (or compiled dynamically from bytecode by the JIT translator).

Compiled object files are bigger than bytecode files. Therefore, the memory requirements are bigger if machine compiled code is used - at least if a single Smalltalk/X application is running. However, on systems which support shared libraries, this code is shared amongst all those applications (which is not the case with interpreted bytecode), therefore, depending on how many such applications are executing, there may be a memory advantage - even with larger object files.
Also, it must be considered, that statically compiled machine code is located in the code segment of the program - i.e. it will only paged into the physical memory when needed and requires much less memory in the objectMemory area - therefore, even when requiring more memory virtually, there is actually often less real memory required.

In addition, static compiled machine code is not loaded into the objectMemory, and therefore not to be considered by the garbage collector. Especially for big projects, this may reduce GC overhead considerably.

Another positive aspect of statically compiled machine code (in contrast to just-in-time compilation) is the guaranteed maximum response time, in which an invoked method is called.
If methods are compiled at execution time, chances are non-zero, that some method(s) have to be compiled on the first call, and an additional delay is introduced.
(unless you have visited all methods previously and the code cache is big enough to hold all methods
- but then, the dynamic memory requirements of a just-in-time system are in the same order as with static compilation ...).

This defined behavior is the main reason for industrial users to prefer static over dynamic compilation.

Configuration Files

This is only relevant for Unix systems. The build process for Windows systems is described below.

Stc can be used like any other (batch-) compiler by calling it directly from the UNIX/DOS command line. However, since there are many possible command line arguments and configuration settings that have to be managed, it is easier and suggested that you use Makefiles to compile classes and build systems.

The system as delivered includes shell scripts and make rules to handle different architectures and configurations. To avoid the need for rewriting all Makefiles for a new architecture, all relevant values have been splittet into machine dependent parts and project (or library) dependent part. The machine dependent parts are included from the configurations folder. The library contents is defined in "Make.proto" and "Make.spec" files.

The configurator (called "CONFIG") creates appropriate symbolic links named "myConf" and "vendorConf" in the configuration folder.

To do so, the configurator uses so called config and rule files, which define all architecture and configuration dependent settings.

Make rules are found in the "rules" subdirectory; config files in subdirectories of "configurations".
You don't have to care for the rule files normally - they are independent of the configuration.
The config files are organized by machine architecture and configuration. They define things like C-compiler flags, include paths, classes to be included in the building process, additional link libraries etc.

In addition, package-lists are used to control which classLibraries are to be built into the system. These are found in the "configurations/PACKS" subdirectory.
Package lists define which objects should be included, config files define how these objects are built.

The generic paths of config files looks like:

    configurations/COMMON/defines
    configurations/architecture/COMMON/defines
    configurations/architecture/configuration/defines
For example, the linux definitions for linux versions above 1.0, with C-optimizer turned on are taken from:
    configurations/COMMON/defines
    configurations/linux/COMMON/defines
    configurations/linux/linux1.x-opt-xxx/defines
and so on. The name of the directory has no semantic meaning - its only for human readers. If you want to create additional configurations, please do so in a new subfolder. Do not change existing configuration files (because your changes will be lost, when you install a new version of ST/X).
When a Smalltalk is built, the name of the configuration is stamped into the executable - look at the launcher's aboutBox, to see the configuration of your system.

Summary:

What is in a Config File

The system as delivered is already setup correctly for your machine - therefore, you may skip reading the next chapters, unless you plan to fiddle around with the C-compiler's flag settings, want to use another compiler, or you need to link against additional system libraries.

Remember, that for all of the following definitions, useful defaults are setup in
"configurations/COMMON/defines" and "configurations/arch/COMMON/defines".

In normal situations, no changes are required. However, if you need anything to be changed, do so in your configuration specific config file; never in a common one.
Since later definitions overwrite previous ones, you can always change things by adding a define to the private defines file.

The following is a short extract - there are many more things that can (but are not required to) be changed:

    CC=                     defines the c-compilers name
			    (not recommended to change)

    O=.o                    extension for object files
			    (not recommended to change;
			     - usually ".o" on UNIX, ".obj" on MSDOS)


    #
    # for "make install" only:
    #
    DESTBINDIR=             where are binaries to be installed
    DESTLIBDIR=             where are libraries to be installed
    DESTINCLDIR=            where are include files to be installed
    DESTMANDIR=             where are man pages to be installed

    #
    # for additional directories and libs (see below)
    #
    OTHERLIBS=              specifies names of other (c-)libraries to be
			    included in the final link

    #
    # Xlib stuff
    #
    XINCLUDE=               path to X include files
    LIBX=                   whats the name of your X-lib
    LIBXEXT=                whats the name of your Xext-lib
    X_LIB_DIR=              path to where X-libraries are found


    #
    # stc compiler flags
    #
    STCCONFOPT=             arguments passed to stc

    #
    # c compiler flags and (preprocessor) defines
    #
    DEFS=                   addidtional defines passed to the c-compiler
    XDEFS=                  like DEFS, for XWindow-related files/classes

    OPT=                    addidtional optimizer flags passed to the c-compiler
			    (typically something like -O6 -m486 ...)

    #
    # additional individual class objects
    #
    EXTRA_CLASSES=          extra individual compiled classes to be
			    included in the final link. These are classes
			    that do not come from class libraries.

    EXTRA_OBJ=              the corresponding object file names

The common configuration files define things like relative path names (within the ST/X file hierarchy), make rules etc.
Most important (and of general interest) are the following definitions, which can be used in "Make.proto" files:
    INCLUDE=                the relative path to the include directory

    STC=                    the relative path to the stc compiler
			    (usually: $(TOP)/stc/stc, but may be redefined to refer
			     to an stc in some other directory)

    LIBBASICDIR=            the name of the directory where the basic classes
			    reside. Similar definitions are found for all the
			    other standard packages.

    BIN_O=                  the suffix of individual binary object files (cc targets)
			    (".o" with unix; different on other architectures).
			    Always use this in your "Make.proto" files
			    to remain architecture independent.

    O_EXT=                  the suffix of class library files (stx packages)
			    (".o" or ".obj" on systems
			     which do NOT support shared libraries;
			     ".so" or ".sl" on systems which do)

What is in a Package File

This section can be skipped - it is only of interest if if you want to change the set of libraries & modules which are included in the Smalltalk executable.

As mentioned above, the package files (in "configurations/PACKS") control which class libraries and additional C libraries are to be built and included in the resulting executable.

The entries found there are:

    WORKSTAT1=                  name of the primary Display driver class
				(typically: XWorkstation)

    WORKSTAT2=                  name of the secondary Display driver class
				(typically: GLXWorkstation)

    EXTRA_CLASSES=              names of additional classes, which
				are to be included from individual object
				files (not class libraries)
				Typically: XWorkstation GLXWorkstat

    EXTRA_OBJ=                  names corresponding object file names
				Typically: $(LIBVIEWDIR)/XWorkstat$(BIN_O)

    OTHERLIBDIRS=               other directories, which the build process
				should visit and `make'

    CLASSLIBDIRS=               directories containing class library sources
				and `Make.proto' files to be built.

    LIBOBJS=                    names of classLibrary objects to be included
				in the link.

    LIBLIST=                    names of the packages found in above objects.
				Typically, these correspond to the file
				names, but in rare cases, these names could
				differ.
The above information may not be up to date, when you read this document.
Examine the files found in configurations/PACKS for more information.

Recompiling the System in Part or Fully

Although recompilation of the complete system is easily done with:
Unix:
	cd TOP
	make clobber            - to clean everything
	make                    - make a target system as set by CONFIG

Windows (Borland compiler):
	cd TOP
	bmake clobber           - to clean everything
	bmake                   - make a target system

Windows (VisualC compiler):
	cd TOP
	vcmake clobber           - to clean everything
	vcmake                   - make a target system

Windows (MinGW compiler):
	cd TOP
	mingwmake clobber        - to clean everything
	mingwmake                - make a target system
that takes a long time on some machines. For local changes, you will get a feeling of what needs to be recompiled. For example, after adding a method to a class in "libbasic", only a recompilation of that class and a relink of the libbasic class library is required and you can skip over the full remake.
In this case, you can also type:
	cd libbasic
	make (bmake / vcmake / mingwmake)
	cd ../projects/smalltalk
	make (bmake / vcmake / mingwmake)
which is much faster, as not all directories are visited.

However, whenever instance variables are added to classes which are subclassed somewhere else, these subclasses have to be recompiled as well. The makefile generator has added a dependency section to your Make.proto files - so only subclasses will be recompiled in the full make.

When new source files (i.e. new classes) are added to a classLibrary, add its name to the "Make.proto" file (or regenerate a new one) and type:

	...
	cd theDirectoryWhereTheSourceWasAdded
	make (bmake / vcmake / mingwmake)
	...
	cd ../projects/smalltalk
	make (bmake / vcmake / mingwmake)

What is in a Make.proto File

A Make.spec file lists the classes to be included in a library and possibly subprojects (subdirectories) in which more libraries are to be built.

The Make.proto contains dependency information, additional rules and definitions for Unix builds. Make.proto files are not used with Windows builds - there, all information is contained in the bc.mak file (originally the name was short for "borland-compile", but it is now also used for VisualC and MinGW builds..

Since all architecture and configuration specific things are handled by the config files, Make.proto and Make.spec files need not (should not) include any system dependencies.

Therefore, "Make.proto" and "Make.spec" files are rather short. They only define the name of the library to be created, the subdirectories (if any) that should be visited and the names of the object files, which make up the library.

The required defines are:

    TOP=                            defines the position relative to the TOP
				    directory (see example below)

    ALLSUBDIRS=                     names of subdirectories, where Makefiles
				    are to be created (if any).

    SUBDIRS=                        names of subdirectories (if any), which should
				    be visited during the build process.

    LIBNAME=                        name of the class library which is to be
				    created by this makefile.
				    (empty, if this is not for a classlib)

    all::                           default rule; usually, this simply calls
				    for the 'classLibRule' target, which creates
				    the required help files, object file(s) and
				    a prelinked classLibrary (possibly a shared one).
				    Additional C file targets should go here

    OBJS=                           names all object files which are to be
				    built and/or included in the classLibrary.

optional are definitions which change compilation flags:
    STCOPT=                         stc options; defaulted in COMMON/defines
				    There is usually no need to redefine this in
				    individual Make.proto files.

    STCLOCALOPT=                    stc options to be used in addition
				    to standard settings;
				    additional package or optimization
				    flags should be given here.
				    For example: 'STCLOCALOPTS=+optspace3'
optional but highly recommended rules are:
    clean:                          a rule to cleanup all intermediate files,
				    but not the library targets - so that the
				    executable can be relinked without recompilation.
				    Typically, all object files are removed here.

    clobber:                        a rule to cleanup everything
				    Ideally, the directory is left in the state it
				    had initially.
				    (Makefiles are usually kept)
				    Typically, all object files and library files
				    are removed here.

    # BEGINMAKEDEPEND               the "make mf" rule will
    # ENDMAKEDEPEND                 insert dependency information in between
				    those. Always include those two keywords at
				    the end of your proto file.

For example, the "Make.proto" for the basic class library looks (somewhat) like:
    TOP=..                          - its directly under TOP
    SUBDIRS=                        - I have no subdirectories to make

    LIBNAME=libbasic                - thats the name of the classlibrary

    STCOPT=$(LIBBASIC_STCOPT)       - override default options
				      (LIBBASIC_STCOPT is +optinline)

    STCLOCALOPT=-P(stx:libbasic) \  - define the package of all classes
		-warnGlobalAssign \   compiled here, turn off some warnings
		+optinline2           and turn on more inlining


    all::   classListRule           - default rule: create abbrev file
				      objects, classList and a prelinked
				      class library

    OBJS=   Object.$(O) \           - names all object files which are
	    Boolean.$(O) \            to be created from corresponding .st
	    ...                       files. Notice the $(O) instead of .o;
				      This allows the same Make.proto to be
				      be used on MSDOS and Mac systems (where object
				      files are named differently).

    # BEGINMAKEDEPEND               - template for dependencies
    # ENDMAKEDEPEND

How to get an Initial Make.proto File

There are three ways of optaining a Make.proto file; only the first is now recommended. The other 2 are for experienced hackers, who know exactly what they are doing. The first method should always generate a consistent set of Make and build support files. It is done either via the browser's "Check in build-support files" or via the packager's build-UI.

The stmkmp scans the current directory for Smalltalk-source files (files ending in '.st') and generates a Make.proto file for them (it was used initially, before the UI tools were present).

Creating Binary Class Libraries

The following gives step-by-step information on how to add a new class library. For all of your new classes, this is the recommended way of doing things. Adding classes to existing directories may lead to problems and/or added work whenever a new ST/X release is delivered and installed: you would have to reedit all of your changed Make.proto files.

Lets assume, that your new library is to be called "libfoo" and shall contain the classes called Foo, Bar and Baz.

First of all, you should not package it under the "stx:" module. (i.e. do not create it under the "stx" folder). The "stx:" module prefix is reserved for the base system.

Use a private module prefix (usually your company name). This implies, that the files will be located in a sibling folder of the "stx" folder (i.e. a subfolder of "stx"'s parent folder).

In the following description, let's assume this is called "myCompany".

  1. Write the Classes
    Enter, test and debug the classes in the existing environment (i.e. in the browser). Change their package (also called project) identifier to "myCompany:libfoo", or better start separating by projects right from the start, give it a nice project name, and name it "myCompany:project1/libfoo".

    Another good idea is to put classlibraries which are useful for multiple projects into a separate folder (such as a "common" folder).

  2. Create a home for the sources
    Create a directory named "myCompany" as a sibling to the "stx" folder.
    Create a subdirectory named "project1" under the "myCompany" folder.
    Create a subdirectory named "libfoo" under the "project1" folder.

    Be warned again: to avoid additional work and frustration, when a new ST/X release is installed, please DO NOT create your "libfoo" directory below the ST/X top.

    Thus, your folder hierarchy should look like:

        someDir/stx/                        - home of stx
    	   ... libbasic                 - as delivered
    	   ... configurations           - as delivered
    	   ... rules
    	   ...
    
        someDir/<myCompany>/common    - your common classLibs
    
        someDir/<myCompany>/<project1>  - one of your project - beside stx
    	    ... <project1>/classLib1      - further subdivided if required
    	    ... <project1>/classLib2      - further subdivided if required
    
        someDir/<myCompany>/<project2>  - another project - beside stx
    	    ... <project2>/classLib1      - further subdivided if required
    	    ... <project2>/classLib2      - further subdivided if required
    

    This setup will avoid any conflict, when additional classLibraries are integrated from other vendors, or a new ST/X revision is installed. (also, note that additional addOn packages as delivered by eXept (such as ASN1, OSI etc.) will go into "someDir/exept/..." and not conflict with your files.

    After all of this, let's assume that your new directory is called:

       .../myCompany/project1/libfoo
    
    and it is locate beside the ST/X tree, which is:
       .../stx/...
    

  3. Develop and debug your application

  4. Move them to the desired package (browser's "Move to Package" menu function)

  5. Create the source files
    Change the browser's perspective to "Package"-view and save your package sources using "Save Each In..." in the SystemBrowser.

    Notice, that the plain "Save" menu function creates the files in your current directory (which is usually "projects/smalltalk"). So please use the "Save Each Into..." menu function. Otherwise, you will have to move the files manually into "$TOP/myCompany/libfoo".

    Since stc requires that each class is in a separate source file, the fileOut-category or fileOut-package functions cannot be used here (as they create one huge file containing all classes).
    Instead, use fileOut-each, which saves each class in a separate sourcefile.

    Alternatively (if you have a SourceCodeManager configured), check the classes into the repository in the systemBrowser (possibly into a new module / module-package), open a terminal view (xterm / cmd-console), and check them out with the 'co' shell command.

    For example, if you have a CVS repository available, you should check your classes into the repository directly from within the system browser ("Check In" menu function).

  6. Create Built-Support Files
    In antient times "Make.proto" files had to be edited manually. This is no longer needed. Use the browser's "Fileout Built Support Files" menu function, to create all required files (this will create Make.proto, Make.spec, bmake, vcmake and mingwmake files).

    If you have a source code repository, you should check the built support files into it right from within the browser.

  7. Compile your library
    While testing, you probably do not want to start the (time consuming) global make in TOP, but instead only compile things local to libfoo.
    	cd libfoo
    	make
    
    this should (after a while) leave you with your new classLibrary libfoo in that directory.
    Depending on the architecture and/or configuration, the filename extension of the library varies; any of "libfoo.a", "libfoo.obj", "libfoo.o" or "libfoo.so" may be found there after the make. Don't care for this detail - the make rules create whatever is best for your architecture.
    (For example, on some systems archives (".a" extension) lead to very long link times - on those, classLibraries are prelinked, relocatable objects (".obj"). Some do not allow ".obj", therefore ".o" is used. Finally, some support shared libraries named ".so", ".sl" or even ".dll")
    If you plan to pass the compiled class library to others, all you have to distribute is the libfoo object just created.
    The others (those who include your binary) must change their config files too, but only have to perform the following (and final) step.

  8. Get the classes into the executable
    If you are on a system which supports dynamic loading ( SGI Indy, linux a.out or ELF, SUNOS, Solaris, Unixware SYS5.4, alpha OSF1 and WIN32 systems), you can attach this library to your running system without leaving it (use "fileIn" in the File Browser) or via the package load dialog, or programmatically, by evaluating.
        ...
        Smalltalk loadPackage:'<myCompanyName>:project1/libfoo'.
        ...
    

    Alternatively, you can add a line to the "private.rc" or "startup.rc" scripts, which loads the library at startup time:

        ...
        Smalltalk fileIn:'name-of-your-class-object-file-without-suffix'.
        ...
    
    This is portable in that it determines the required file suffix itself (".so" / ".sl" or ".dll", depending on the system)

    However, the recommended interface is loadPackage:

        ...
        Smalltalk loadPackage:'<myCompanyName>:project1/libfoo'.
        ...
    
    because that will try hard to load the package, even if it is not compiled to a binary class library (i.e. it will load from sources, if no dll is present).

    On all systems which do NOT support dynamic loading, you have to leave any running Smalltalk, compile your class libraries, relink the Smalltalk executable and start a new (this time with those new classes being part of the built-in classes).

    Since saved snapshot images are (currently) unusable after a system rebuild, it is now time to save all your work in source form (i.e. fileOut or checkIn all other classes and make certain that you can reconstruct your universe later from these and/or the changes file).

    The Smalltalk executable is rebuilt with:

        cd projects/smalltalk
        make (bmake / vcmake / mingwmake)
    
Congratulations ! you should now find your foo-classes in the system when starting the new executable. (use "smalltalk -I" to have it ignore any existing snapshot file.)

For your tests, always keep the old snapshot, Smalltalk executable and dlls around by copying the "projects/smalltalk" folder. Remember: snapshots only work with the corresponding binaries.

Adding more Classes

Once you are through the above hard work, adding more classes is easy: in the system browser, select the package definition class (i.e. the class named "myCompany_project1_libfoo") and select the "Update Project Definitions" menu item, found in the "class"-"generate" menu. Then fileout or checkin the project (including the built support files), open a shell window, checkout and remake the library there.

As above, a remake of the Smalltalk executable itself is only required if your system does not support shared libraries.
If it does you can even switch to the new classLibrary in the running system, by: unloading any old loaded classLibrary first (using the launcher's "System"-"Modules" dialog), and re-loading the new shared library.

WARNING:
Depending on the C-Code / C-libraries you have included, this reloading may fail occasionally, if there are leftOver references to static data or functions somewhere in the C-code.
This may even lead to a crash in some situations.

We highly recommend saving your work before any reload - over time, you will get a feeling for that ;-)

Adding more Class Libraries (to the Base System)

Once you have written a number of private class libraries, you may eventually want them to be automatically loaded upon startup. Or, for deployable standalone applications, you may want to build an executable, which has them already included.

You have multiple choices to realize this:

  1. Define it as "Automatically Loaded on Startup"
    this adds the library to a list found in your preferences file. Thus, it will be a personal setting, which is easily undone or extended in the future. However, this is not a solution for standalone executables.

  2. Add an entry to a customized "start.rc" file
    Both the IDE and standalone projects will read a startup script, named "appName.rc". The file is assumed to be present in the binary's folder. By adding a line like "Smalltalk loadPackage:'libfoo'" or "Smalltalk fileIn:'libfoo'", any custom setup is possible.

  3. Build a standalone executable, which has the library already in
    Add the library to the list of mandatory prerequisites and build a standalone executable.

Interfacing C Functions

To add C functions, you have various options of how to interface to them, and where they are located:
  1. In a separate dll, calling them as ExternalLibraryFunction
  2. In a separate dll, calling them via Smalltalk wrapper methods
  3. Inside the classlibrary, within the classes source file, calling via Smalltalk wrapper methods
  4. In the main.c source file, calling them as custom ExternalFunction
  5. Inline code in a method

In a separate dll, calling as ExternalLibraryFunction

This mechanism does not require any special build or compilation steps. It is used, when existing C-libraries have to be attached. Especially, if you do not have the source code or if it is a system dll.

For each function to be called, you need one wrapper method, which contains a single line such as:

    primStartPage:hIn
	<apicall: int32 "StartPage" (handle) module: "gdi32.dll" >
this creates a Smalltalk method (typically on the class side), which call the "StartPage" function, with one argument of "handle" type in the the "gdi32.dll". The return value is an int32.

The good news about this is that you can call any function without a need for any compilation. It works with stc-compiled and with bytecode methods.
However, you have to correctly specify the argument- and return types, and on Windows also the calling convention ("api" or "c").

This mechanism uses the libffi foreign function interface, and has therefore a little overhead in calling (a few microseconds).

The loading of the shared library is fully automatic. It will be done lazily, when the very first function inside that dll is called.

In a separate dll, calling via Smalltalk wrapper methods

In this setup, the C function are also in a separate dll, but the calling is done by little wrapper methode, which convert Smalltalk objects as arguments and create return value objects. The library to call must be linked against the class library, in which the call-wrappers are.

Inside the classlibrary, within the classes source file

In this setup, the C function's source code is in the class source file, and compiled with the class. The code will be completely inside the binary class libarary, and no additional dll needs to be deployed or loaded.

For this, put the C functions into the "primitiveFunctions" section of the class source, and wrapper methods to call them. Many ST/X methods use this mechanism, to tune special cases in separate C-functions. Take a look at the Image- or the XWorkstation classes for concrete examples. (for example, some decompressors are found in the Image-class's primitiveFunctions section)

In the main.c source file, calling them as custom ExternalFunction

This is a simple "poor man's" approach to call external functions, which is kind of in-between the above mechanisms. It only requires the recompilation of a single file ("main.c"), which is recompiled aynway for stand alone applications.

Place the code as custom functions there, and call them via "ExternalFunction callCustomFunction:".

Inline code in a method

Here, the C-functionality is not in a separate function, but right in the method itself. This allows for the fastest entry into the C-code, as no separate calls or argument conversions are required. All of ST/X's primitives are written in that style (take a look at the Array-, String and other classes from libbasic or libview as examples). For details on primitive code, please read: ``How to write primitives & inline C code''):

We recommend a combination of the "Inline" and "Code in the class library" mechanisms. However, this choice is only a good one for a small number of C functions, of which the source code is available.

Adding C Libraries

Additional C libraries are included in the link of the Smalltalk executable by specifying them as "OTHERLIBS" in the config file. For example, if you have a C library called "libUseful.a", placed under TOP/libfoo/cStuff, the line should look like:
    OTHERLIBS=$(TOP)/libfoo/cStuff/libUseful.a
Of course, if the library is located in some standard place (i.e. in /usr/lib or /usr/local/lib), you can also write:
    OTHERLIBS=-lUseful
Read the C-compiler's and linker's man pages if you need more information on this.

All OTHERLIBS are linked in the order specified; thus, if you have dependencies between your extra libraries, these may be fixed by changing the order. For example, if you have two libraries "libUseful1.a" and "libUseful2.a", of which the second needs entries in the first, you will get a link error if the config define looks like:

    OTHERLIBS=$(TOP)/libfoo/cStuff/libUseful1.a \
	      $(TOP)/libfoo/cStuff/libUseful2.a
in this case, change the order as in:
    OTHERLIBS=$(TOP)/libfoo/cStuff/libUseful2.a \
	      $(TOP)/libfoo/cStuff/libUseful1.a

An Example for C Interfacing

In the following, an interface to C functions which are compiled from separate sources is shown.
For the example, we assume that a directory "libfoo" exists, and the library is to be named "libfoo" as well.
For better structuring, we place the C sources into a subdirectory of "libfoo" called "cstuff" and create a C library called "cstuff.a" there.
The C sources are in "libfoo/cstuff/module1.c":
    cFuntion1() {
	printf("here is your C function call ....\n");
    }
and "libfoo/cstuff/module2.c":
    cFuntion2(arg)
	int arg;
    {
	printf("here is your 2nd C funtion; the args value is %d\n");
    }
The interface wrapping code for Smalltalk is in "libfoo/CInterface.st":
    Object subclass:#Cinterface
	   instanceVariableNames:''
	   classVariableNames:''
	   poolDictionaries:''
    !

    !Cinterface class methodsFor:'C calling'!

    cFuntion1
    %{
	cFuntion1();
    %}
    !

    cFuntion2:argument
    %{
	if (__isSmallInteger(argument)) {
	    cFuntion2( _intVal(argument) );
	}
    %}
    ! !
The "Make.proto" to compile all of these is:
    TOP=..
    LIBNAME=libfoo

    all::   CSTUFF abbrev.stc objs genClassList $(OBJTARGET)

    objs::  CInterface.$(O)

    CSTUFF::
	    (cd cstuff ; make)
The C library is built by the following rules in "cstuff/Makefile":
    all:    module1.o module2.o
	    ar rv cstuff.a module1.o module2.o
Thats it, after a "make" in libfoo, you will find "libfoo.obj" (or "libfoo.so") and "libfoo/cstuff.a" ready for linkage.

To get those into the executable, your config file should have the definitions:

    OTHERLIBDIRS=$(TOP)/libfoo

    PRIVATEOBJS=$(TOP)/libfoo/libfoo$(OBJNAME)

    PRIVATE_SO=$(TOP)/libfoo/libfoo$(SO_NAME)

    PRIVATELIBS=libfoo

    OTHERLIBS=$(TOP)/libfoo/cstuff/cstuff.a
The files of the example can be found in "doc/coding/libfoo_example".

For details on the primitive wrapper code, read ``How to write primitives & inline C code''.

Automatic building

Automatic creation and building via the project management is being prepared. However, at this time, this feature is not fully implemented and things should be done manually.

Once completed, you will be able to create per project directories, Make.protos and the sources by the click of a button.


Copyright © 1995 Claus Gittinger, all rights reserved

<cg at exept.de>

Doc $Revision: 1.30 $ $Date: 2021/03/13 18:24:51 $