Difference between revisions of "MorphOS API and Its Organization"

From MorphOS Library

(Contents++;)
m (Formatting.)
 
(24 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
''Grzegorz Kraszewski''
 
''Grzegorz Kraszewski''
 +
----
 +
<small>This article in other languages: [[Organizacja API MorphOS-a|Polish]]</small>
  
  
An Application Programmer Interface of an operating system consists of thousands of functions usually. MorphOS is no exception here. Its kernel is not monolithic however. The API is functionally (and physically) divided into libraries. Only a few largest libraries contain more than 50 functions. A core set of most important libraries is contained in the system boot image. The rest is placed on the system partition in ''MOSSYS:Libs'' (libraries delivered with the system) and ''SYS:Libs'' (third party libraries) directories. Disk based libraries are loaded on demand. All these libraries are shared, it means all processes using a library execute the same code loaded to memory once.
+
An Application Programmer Interface of an operating system usually consists of thousands of functions. MorphOS is no exception here. Its kernel is not monolithic however. The API is functionally (and physically) divided into libraries. Only a few of the largest libraries contain more than 50 functions. A core set of the most important libraries is contained in the system boot image. The rest are placed on the system partition in ''MOSSYS:Libs'' (libraries delivered with the system) and ''SYS:Libs'' (third party libraries) directories. Disk based libraries are loaded on demand. All these libraries are shared, which means all processes using a library execute the same code loaded to memory once.
 +
 
  
 
==Libraries Overview==
 
==Libraries Overview==
Line 8: Line 11:
 
MorphOS comes with over 100 different libraries. Not all of them are listed below, just the most common ones. Browse the system autodocs in the SDK for more.
 
MorphOS comes with over 100 different libraries. Not all of them are listed below, just the most common ones. Browse the system autodocs in the SDK for more.
  
* '''exec.library''', the master one. This is the system core, responsible for processes scheduling, control and creation, communication between processes, memory management, managing other libraries and overall system control. This is the only library which is always opened and cannot be closed.
+
* '''exec.library''', the master library. This is the system core, responsible for process scheduling, control and creation, communication between processes, memory management, managing other libraries and overall system control. This is the only library which is always open and cannot be closed.
  
* '''dos.library''', responsible for file and console input/output. Provides interface to advanced filesystem functions (like scanning directories for example). Cooperates with ''exec.library'' in process creation. Delivers basic system time services.
+
* '''dos.library''', responsible for file and console input/output. Provides an interface to advanced filesystem functions (like scanning directories for example). Cooperates with the ''exec.library'' in process creation. Delivers basic system time services.
  
 
* '''graphics.library''', is responsible for low-level graphics functions like drawing pixels and other primitives, copying rectangular blocks of display, scrolling etc. Many programs do not use it directly.
 
* '''graphics.library''', is responsible for low-level graphics functions like drawing pixels and other primitives, copying rectangular blocks of display, scrolling etc. Many programs do not use it directly.
  
* '''intuition.library''', delivers an intermediate level graphics interface objects like screens and windows. Interfaces to user input devices (mouse and keyboard to name a few). Provides very basic user controls (gadgets). Provides also BOOPSI (''Basic Object Oriented System for Intuition''), a language independent object oriented programming framework, used commonly by other components.
+
* '''intuition.library''', delivers intermediate level graphics interface objects like screens and windows. Interfaces to user input devices (mouse and keyboard to name a few). Provides very basic user controls (gadgets). Provides also [[Short BOOPSI Overview|BOOPSI]] (''Basic Object Oriented System for Intuition''), a language independent object oriented programming framework, used commonly by other components.
  
* '''muimaster.library''', the main interface to MUI (''Magic User Interface''), which is the MorphOS high level GUI toolkit. Provides complete, object oriented framework (based on BOOPSI) for GUI driven applications.  
+
* '''muimaster.library''', the main interface to MUI (''Magic User Interface''), which is the MorphOS high level GUI toolkit. Provides a complete, object oriented framework (based on BOOPSI) for GUI driven applications and a rich set of GUI objects.  
  
* '''locale.library''', is responsible for system and applications internationalization. This simple yet powerful subsystem allows for supporting multiple language versions of program with single executable, also provides localization data such as date format, local currency, timezone, number grouping and more.
+
* '''locale.library''', is responsible for system and application internationalization. This simple yet powerful subsystem allows for supporting multiple language versions of a program with a single executable, also provides localization data such as date format, local currency, timezone, number grouping and more.
  
* '''bsdsocket.library''' is an interface for TCP/IP networking, compatible with BSD sockets. What is unusal with this library, it is neither built into kernel, nor placed on disk. The TCP/IP stack creates it in memory dynamically.
+
* '''bsdsocket.library''' is an interface for TCP/IP networking, compatible with BSD sockets. What is unusual with this library, is that it is neither built into the kernel, nor placed on disk. The TCP/IP stack creates it in memory dynamically.
  
  
Line 27: Line 30:
 
In typical cases it is pretty automatic. The only thing which has to be done is including the main library header file, which is ''<proto/[libname].h>'', for example ''<proto/exec.h>'', ''<proto/muimaster.h>'' and so on. Library opening and closing is handled automatically by the startup code provided by either ''libnix'' or ''ixemul.library''. Then one can just use functions from the library.
 
In typical cases it is pretty automatic. The only thing which has to be done is including the main library header file, which is ''<proto/[libname].h>'', for example ''<proto/exec.h>'', ''<proto/muimaster.h>'' and so on. Library opening and closing is handled automatically by the startup code provided by either ''libnix'' or ''ixemul.library''. Then one can just use functions from the library.
  
 +
A few big libraries have separate subdirectories in the system include tree. Examples of such libraries are ''exec.library'', ''dos.library'' and ''graphics.library''. Header files in these directories contain definitions of constants, data structures, attributes etc. used by the library, divided by functionality. Including of these headers depends on which functions are used in the application, for example to use ''exec.library'' memory allocation functions one has to include the ''<exec/memory.h>'' header.
  
A few big libraries have separate subdirectories in the system include tree. Examples of such libraries are ''exec.library'', ''dos.library'' or ''graphics.library''. Header files in these directories contain definitions of constants, data structures, attributes etc. used by the library, divided by functionality. Including of these headers depends on functions used in the applications, for example to use ''exec.library'' memory allocation functions one has to include ''<exec/memory.h>'' header.
+
Other libraries have a single header file in the ''libraries'' directory. Examples are ''<libraries/locale.h>'' or ''<libraries/mui.h>'' (the latest is some deviation from the naming rule). This single header may be automatically included from the ''proto'' file or not.
 
 
 
 
Some libraries prefer to have one single header file in ''libraries'' directory. Examples are ''<libraries/locale.h>'' or ''<libraries/mui.h>'' (the latest is some deviation from the naming rule). This single header may be automatically included from ''proto'' file or not.
 
 
 
  
 
There are a few cases, where automatic library handling does not work, or cannot be used.
 
There are a few cases, where automatic library handling does not work, or cannot be used.
Line 39: Line 39:
 
* Custom startup code (linking with '''&minus;nostartfiles''').
 
* Custom startup code (linking with '''&minus;nostartfiles''').
 
* Opening libraries in a subprocess.
 
* Opening libraries in a subprocess.
 +
* Dynamic on-demand library opening.
 +
* The library base has been defined in the application code. Autoopening for this library is automatically disabled in this case.
  
In these cases libraries have to be handled manually.
+
In all of these cases, libraries have to be handled manually.
  
  
 
==Manual Library Opening and Closing==
 
==Manual Library Opening and Closing==
  
 +
While not as convenient as automatic handling, manual opening and closing of libraries is not very complicated. A ''library base'' variable has to be defined, then two functions from ''exec.library'': ''OpenLibrary()'' and ''CloseLibrary()'' have to be used.
 +
 +
The library base is defined in its ''proto'' file (the main header) as a global variable. It is a pointer to a ''Library'' structure, which should be treated as an opaque pointer. The result returned by ''OpenLibrary()'' should be placed in the library base before any function of the library is called. Then, when the library is no longer needed, it should be closed with ''CloseLibrary()'' using its base as the argument. The layout for using the hypothetical ''foobar.library'' is as follows:
 +
 +
/* inside <proto/foobar.h> */
 +
 +
struct Library *FoobarBase;
 +
 +
/* inside application */
 +
 +
#include <proto/foobar.h>
 +
 +
if (FoobarBase = OpenLibrary((STRPTR)"foobar.library", 7))
 +
{
 +
  /* use library functions here */
 +
 +
  CloseLibrary(FoobarBase);
 +
}
 +
 +
The ''OpenLibrary()'' call takes two parameters. The first one is just the name of the library to be opened. It is only the name, without path. MorphOS searches a few locations for the library in the following order:
 +
* MOSSYS:Libs/
 +
* LIBS:
 +
* current directory of the application
 +
* PROGDIR:Libs/
 +
In the fourth path ''PROGDIR:'' is an automatic assign pointing to the directory containing the application executable.
 +
 +
The second parameter of ''OpenLibrary()'' is the minimum required version. Zero here opens any version, any positive number means "this version or higher". There is no straightforward way for requesting a particular version of a library. It can be noticed that this approach only works if newer versions of a library are always backward compatible with older ones. On the other hand it avoids having multiple versions of the same library in the system, which is a common problem with Linux shared objects.
 +
 +
The value returned by ''OpenLibrary()'' should be always checked against NULL. Even a library built into the boot image may fail to open (because of a memory shortage for example, or having too low a version). Printing some error message in case of a fail is definitely a good idea.
 +
 +
Every successful ''OpenLibrary()'' call must be matched with ''CloseLibrary()''. Resource leak is created otherwise. It also makes it impossible to flush unused library from memory.
 +
 +
There are two special cases for manual library opening and closing: ''exec.library'' and ''dos.library''. The first one is always open and cannot be closed, as stated above. The library base for it (named ''SysBase'') is defined and initialized in the startup code. If declared manually in an application's source code, it should be declared as an ''extern''. The ''dos.library'' is opened and closed as with any other library, but because the startup code needs it, the ''DOSBase'' is already defined and initialized there. As a result the application does not need to open ''dos.library'' before using it. If declared in an application, ''DOSBase'' should be an ''extern'' too.
 +
 +
 +
<small>As with the Amiga historical heritage, some of the most important library bases (''SysBase'', ''DOSBase'', ''IntuitionBase'', ''GfxBase'' and a few more) are not defined as ''struct Library*'' but as pointers to library specific structures. Direct poking of these structures was unavoidable in early AmigaOS versions. In MorphOS it is neither needed nor recommended.
 +
One can avoid the above definitions (which forces unnecessary typecasting in ''OpenLibrary()'' and ''CloseLibrary()'') by #defining __NOLIBBASE__ symbol before including ''proto'' files. This disables library bases definitions. All bases can (and must) be then explicitly defined in the code as pointers to ''struct Library''.
 +
 +
Also for traditional reasons, names of some library bases do not follow the ''[Libname]Base'' scheme. The most important deviations are: '''SysBase''' for ''exec.library'', '''DOSBase''' for ''dos.library'' (capitalization), '''GfxBase''' for ''graphics.library'', '''MUIMasterBase''' for ''muimaster.library'' (capitalization), '''CyberGfxBase''' for ''cybergraphics.library''. In any case the base name can be checked by looking at the library ''proto'' header.
  
==Technical Insight==
+
Using the proper base name is very important, as it is used as an '''implicit argument''' in all the calls of library functions.</small>

Latest revision as of 09:37, 7 April 2011

Grzegorz Kraszewski


This article in other languages: Polish


An Application Programmer Interface of an operating system usually consists of thousands of functions. MorphOS is no exception here. Its kernel is not monolithic however. The API is functionally (and physically) divided into libraries. Only a few of the largest libraries contain more than 50 functions. A core set of the most important libraries is contained in the system boot image. The rest are placed on the system partition in MOSSYS:Libs (libraries delivered with the system) and SYS:Libs (third party libraries) directories. Disk based libraries are loaded on demand. All these libraries are shared, which means all processes using a library execute the same code loaded to memory once.


Libraries Overview

MorphOS comes with over 100 different libraries. Not all of them are listed below, just the most common ones. Browse the system autodocs in the SDK for more.

  • exec.library, the master library. This is the system core, responsible for process scheduling, control and creation, communication between processes, memory management, managing other libraries and overall system control. This is the only library which is always open and cannot be closed.
  • dos.library, responsible for file and console input/output. Provides an interface to advanced filesystem functions (like scanning directories for example). Cooperates with the exec.library in process creation. Delivers basic system time services.
  • graphics.library, is responsible for low-level graphics functions like drawing pixels and other primitives, copying rectangular blocks of display, scrolling etc. Many programs do not use it directly.
  • intuition.library, delivers intermediate level graphics interface objects like screens and windows. Interfaces to user input devices (mouse and keyboard to name a few). Provides very basic user controls (gadgets). Provides also BOOPSI (Basic Object Oriented System for Intuition), a language independent object oriented programming framework, used commonly by other components.
  • muimaster.library, the main interface to MUI (Magic User Interface), which is the MorphOS high level GUI toolkit. Provides a complete, object oriented framework (based on BOOPSI) for GUI driven applications and a rich set of GUI objects.
  • locale.library, is responsible for system and application internationalization. This simple yet powerful subsystem allows for supporting multiple language versions of a program with a single executable, also provides localization data such as date format, local currency, timezone, number grouping and more.
  • bsdsocket.library is an interface for TCP/IP networking, compatible with BSD sockets. What is unusual with this library, is that it is neither built into the kernel, nor placed on disk. The TCP/IP stack creates it in memory dynamically.


How to Use a Library in an Application

In typical cases it is pretty automatic. The only thing which has to be done is including the main library header file, which is <proto/[libname].h>, for example <proto/exec.h>, <proto/muimaster.h> and so on. Library opening and closing is handled automatically by the startup code provided by either libnix or ixemul.library. Then one can just use functions from the library.

A few big libraries have separate subdirectories in the system include tree. Examples of such libraries are exec.library, dos.library and graphics.library. Header files in these directories contain definitions of constants, data structures, attributes etc. used by the library, divided by functionality. Including of these headers depends on which functions are used in the application, for example to use exec.library memory allocation functions one has to include the <exec/memory.h> header.

Other libraries have a single header file in the libraries directory. Examples are <libraries/locale.h> or <libraries/mui.h> (the latest is some deviation from the naming rule). This single header may be automatically included from the proto file or not.

There are a few cases, where automatic library handling does not work, or cannot be used.

  • Third party libraries. Most of them are not included in the autoopen feature.
  • Custom startup code (linking with −nostartfiles).
  • Opening libraries in a subprocess.
  • Dynamic on-demand library opening.
  • The library base has been defined in the application code. Autoopening for this library is automatically disabled in this case.

In all of these cases, libraries have to be handled manually.


Manual Library Opening and Closing

While not as convenient as automatic handling, manual opening and closing of libraries is not very complicated. A library base variable has to be defined, then two functions from exec.library: OpenLibrary() and CloseLibrary() have to be used.

The library base is defined in its proto file (the main header) as a global variable. It is a pointer to a Library structure, which should be treated as an opaque pointer. The result returned by OpenLibrary() should be placed in the library base before any function of the library is called. Then, when the library is no longer needed, it should be closed with CloseLibrary() using its base as the argument. The layout for using the hypothetical foobar.library is as follows:

/* inside <proto/foobar.h> */

struct Library *FoobarBase;
/* inside application */

#include <proto/foobar.h>

if (FoobarBase = OpenLibrary((STRPTR)"foobar.library", 7))
{
  /* use library functions here */

  CloseLibrary(FoobarBase);
}

The OpenLibrary() call takes two parameters. The first one is just the name of the library to be opened. It is only the name, without path. MorphOS searches a few locations for the library in the following order:

  • MOSSYS:Libs/
  • LIBS:
  • current directory of the application
  • PROGDIR:Libs/

In the fourth path PROGDIR: is an automatic assign pointing to the directory containing the application executable.

The second parameter of OpenLibrary() is the minimum required version. Zero here opens any version, any positive number means "this version or higher". There is no straightforward way for requesting a particular version of a library. It can be noticed that this approach only works if newer versions of a library are always backward compatible with older ones. On the other hand it avoids having multiple versions of the same library in the system, which is a common problem with Linux shared objects.

The value returned by OpenLibrary() should be always checked against NULL. Even a library built into the boot image may fail to open (because of a memory shortage for example, or having too low a version). Printing some error message in case of a fail is definitely a good idea.

Every successful OpenLibrary() call must be matched with CloseLibrary(). Resource leak is created otherwise. It also makes it impossible to flush unused library from memory.

There are two special cases for manual library opening and closing: exec.library and dos.library. The first one is always open and cannot be closed, as stated above. The library base for it (named SysBase) is defined and initialized in the startup code. If declared manually in an application's source code, it should be declared as an extern. The dos.library is opened and closed as with any other library, but because the startup code needs it, the DOSBase is already defined and initialized there. As a result the application does not need to open dos.library before using it. If declared in an application, DOSBase should be an extern too.


As with the Amiga historical heritage, some of the most important library bases (SysBase, DOSBase, IntuitionBase, GfxBase and a few more) are not defined as struct Library* but as pointers to library specific structures. Direct poking of these structures was unavoidable in early AmigaOS versions. In MorphOS it is neither needed nor recommended. One can avoid the above definitions (which forces unnecessary typecasting in OpenLibrary() and CloseLibrary()) by #defining __NOLIBBASE__ symbol before including proto files. This disables library bases definitions. All bases can (and must) be then explicitly defined in the code as pointers to struct Library.

Also for traditional reasons, names of some library bases do not follow the [Libname]Base scheme. The most important deviations are: SysBase for exec.library, DOSBase for dos.library (capitalization), GfxBase for graphics.library, MUIMasterBase for muimaster.library (capitalization), CyberGfxBase for cybergraphics.library. In any case the base name can be checked by looking at the library proto header.

Using the proper base name is very important, as it is used as an implicit argument in all the calls of library functions.