The first thing that fascinated me when I tried programming for the Amiga were the libraries. The first language I used to open and close libraries and use it’s functions was Assembler. At that time it took me some time to understand how libraries worked. This was because of the available information I had. Even today when I look at some of that information I can see that the way it was explained was just too difficult. Would it have been done easier it would have been quicker for me to get to grips with it. The only source of information you had was the magazines and the odd programming book you might be able to purchase. Not like today when you have the internet which gives you access to unlimited resources.
But what are those libraries you keep talking about? The ROM Kernel Manual describes it as follow:
The Amiga has two kinds of libraries: run-time libraries and link libraries. Run-time libraries make up most of the Amiga’s operating system. There is another type of library known as a link library. Even though a link library is a collection of functions just like a run-time library, there are some major differences in the two types.
Run-time libraries
A run-time, or shared library is a group of functions managed by Exec that resides either in ROM or on disk (in the LIBS: directory). A run-time library must be opened before it can be used. The functions in a run-time library are accessed dynamically at run-time and can be used by many programs at once even though only one copy of the library is in memory. A disk based run-time library is loaded into memory only if requested by a program and can be automatically flushed from memory when no longer needed.
Link libraries
A link library is a group of functions on disk that are managed by the compiler at link time. Link libraries do not have to be opened before they are used, instead you must link your code with the library when you compile a program. The functions in a link library are actually copied into every program that uses them.
To sum it up in a simple way: Run-time libraries stored on the hard drive and are opened and closed by the program whenever needed. Link libraries are (actually it’s functions) copied into your program when you are compiling it.
I am discussing the run-time libraries here. I assume you have some understanding of the basics of C programming. If something is not clear (and in future articles) just let me know and I will explain it. Don”t worry if at first it, or something, makes no sense. Sooner or later the penny will drop and it suddenly makes sense.
So what are we going to do for a first example? We are going to open the Intuition library and check if it is opened successfully or not and in both cases display a message.
01 #include <stdio.h>
02 #include <intuition/intuition.h>
03
04 #include <proto/intuition.h>
05 #include <proto/exec.h>
06
07 struct Library *IntuitionBase = NULL;
08
09 struct IntuitionIFace *IIntuition = NULL;
10
11 int main (void)
12
13 {
14
15 /* Opening the Intuition Library */
16 IntuitionBase = IExec->OpenLibrary(“intuition.library”, 50L);
17
18 /* Did we manage to open the Intuition Library? */
19 if (IntuitionBase != NULL)
20 {
21
22 printf (“We opened the Intuition Library!!\n”);
23
24 /* Open the Intuition Interface */
25 IIntuition = (struct IntuitionIFace *) IExec->GetInterface (IntuitionBase, “main”, 1, NULL);
26
27 /* Did we get the Intuition Interface? */
28 if (IIntuition != NULL)
29 {
30
31 printf (“We did get the Intuition Interface!!\n”);
32
33 /* If the Intuition Library Interface is open, close it */
34 IExec->DropInterface((struct Interface *)IIntuition);
35 }
36
37 /* We could not open the Intuition Library Interface */
38 else
39 {
40
41 printf (“Unable to open the Intuition Library Interface!\n”);
42 }
43
44 /* If the Intuition Library is open, close it */
45 IExec->CloseLibrary(IntuitionBase);
46 }
47
48 /* We could not open the Intuition Library */
49 else
50 {
51
52 printf (“Unable to open the Intuition Library!\n”);
53 }
54
55 return 0;
56 }
Type the above code (without the line numbers) in the text editor of your choice or IDE you might use. As you can see in the below screenshot I saved it in the “RAM Disk” with the name “openlibraryos4.c”. Assuming you have installed the OS4 SDK you can compile the code by typing “gcc openlibraryos4.c” in the AmigaShell as shown in the below sceenshot. This will produce the executable with the name “a.out”. If things go as planned you will get the correct out put saying that both the Intuition library and interface could be opened when executing “a.out”.
Congratulations! You just compiled your first working OS4 code. Cool! But of course you like to know what all the code is about. Time to have a look at the source code.
The first 4 lines of code are includes.
01 #include <stdio.h>
02 #include <intuition/intuition.h>
04 #include <proto/intuition.h>
05 #include <proto/exec.h>
“#include” is a preprocessor directive which sounds rather difficult but it is not. It inserts another file into our code. Take for example the <stdio.h> file which includes information regarding the printf statement we are using. The intuition includes for example contain information if you want to display a window. For a simple example as this we don’t need so much includes to get our work done but if you create a larger program you will have more includes to (pardon the pun) include. I usually have a standard set of includes I use even if not all of them are being used. You might get errors during compiling because your code uses a function for which you did not use a include. This might sound rather complicated but after some trial and error from your side it will suddenly make sense.
Before we go to our next two lines a bit of further explanation about libraries is needed. I won’t get to technical but address just enough for you to understand the concept. With the classic Amiga OS you just opened the library you wanted and that was it. With OS4 we also need to use something called a “interface”. With the classic way you open the library and you can use any function from that library. With OS4 we have the interface which sits between the library and the functions it has. Let’s say we want to use a function from the intuition library we use the interface to call/use that function. You can compare it with talking to your wife. The old way would be to directly ask her a question. With the new way we use another person to ask our wife that question. This seems like a great idea (the wife example) but is this not adding extra work (and not to forget make it more difficult) when writing our code? Not really. It is just adding the name of the interface in front of the function. But what about the extra code for getting the interface and check we got it and also close it again? Well (getting ahead now) this is something I will address in part 2 in which you will see we can skip all that opening, checking and closing. Curious? Good!
But why use that interface stuff? Well that has to do with compatibility with the classic software. There is a lot more to it but without scaring you too much we will leave it at this. Let’s have a look at the next two lines.
07 struct Library *IntuitionBase = NULL;
09 struct IntuitionIFace *IIntuition = NULL;
This is usually the part you loose it all. Includes I can follow but this? The two lines declare pointers to structures we need to open the intuition library and also the intuition interface. These structures are actually defined in the <intuition.h> file. When we open the intuition library and get the interface we need to store the value we get back from trying to open them. We can use those values to test if we succeeded in opening both library and interface. We need to set both pointers to zero (NULL) to make sure they don’t point to any random address in memory which might cause the whole system to crash. *IntuitionBase is going to hold the value we get back from trying to open the intuition library and *IIntuition is going to hold the value we get back from trying to open the Intuition interface.
The next line is the start of our program. All programs start with main. To get a better understanding of how C works (it can’t hurt to mention this again) I suggest you check out the Amiga C Programming Tutorial from Michael Ness.
11 int main (void)
The next line is going to (try) open the Intuition Library.
16 IntuitionBase = IExec->OpenLibrary(“intuition.library”, 50L);
Some of you might have spotted the “IExec” part in front of OpenLibrary. This is the interface of the Exec Library. Wait! Stop! Are we not suppose to open this first, including the Exec Library, like we are doing with the Intuition Library? We don’t have to. The Exec Library is always open when OS4 (also with the classic OS) is running. In this case we want to open version 50 or later of the Intuition Library.
Line 19 is going to check if we managed to open the Intuition Library. Since we set the IntuitionBase in the beginning of our program to NULL we know we succeeded if the value of IntuitionBase is not NULL.
19 if (IntuitionBase != NULL)
If we managed to open the Intuition Library our program is going to jump to line 22 and print on our screen that we succeeded in opening the library.
22 printf (“We opened the Intuition Library!!\n”);
If we failed to open the intuition Library the value would still be NULL. If this is the case our program is going to jump to lines 49 – 53.
49 else
50 {
51
52 printf (“Unable to open the Intuition Library!\n”);
53 }
Line 52 will print on our screen that we did not manage to open the intuition Library.
If we successfully opened the Intuition Library and also printed on the screen we did we need to get the interface of the Intuition Library.
25 IIntuition = (struct IntuitionIFace *) IExec->GetInterface (IntuitionBase, “main”, 1, NULL);
Line 25 is trying to get Intuition’s Interface. The value that is being returned after we are trying to get the interface will be stored in IIntuition. IExec->GetInterface is the function that will try and get the interface of the Intuition Library. Looking at the part (IntuitionBase, “main”, 1, NULL); we can see that we are trying to get the Interface of the (IntuitionBase) Intuition Library. Looking further at (IntuitionBase, “main”, 1, NULL); we can see that we are trying to get the main interface and the version number is 1. The last parameter (NULL) is a pointer to a tag list which we won’t discuss here.
What about the (struct IntuitionIFace *) part? Without getting to technical (and loose you all) I can tell you this is called a cast. It will make sure the value returned by IExec->GetInterface is of the type struct IntuitionIFace *.
After we tried to get the Interface we need to check if we are successful.
28 if (IIntuition != NULL)
Line 28 (just like line 19 when we checked if we managed to open the Intuition Library) will check if we got the Interface by checking if the value if IIntuition is not NULL.
If we did manage to get the Interface we will print this as we can see in line 31.
31 printf (“We did get the Intuition Interface!!\n”);
If we failed to get the Interface the program will jump to lines 38-42.
38 else
39 {
40
41 printf (“Unable to open the Intuition Library Interface!\n”);
42 }
Line 42 will print that we did not manage to get the Intuition Library Interface.
If we did manage to open the Intuition Library and get it’s Interface (and of course print it on our screen) we need to end our program which means we need to clean up. The golden rule is to close everything that you open. First part of the clean up starts at line 34.
34 IExec->DropInterface((struct Interface *)IIntuition);
First up we are going to drop the Interface of the Intuition Library. The function DropInterface speaks for itself.
Last part of the clean up starts at line 45. We need to close the Intuition Library.
45 IExec->CloseLibrary(IntuitionBase);
Our program ends at line 55.
55 return 0;
Return can be used to return error codes but we give it the value zero to keep everyone happy. Surely I don’t want to scare (if anyone is still left) what is left of our readers at the very end. That’s it! As I already mentioned earlier in part 2 I will show you how you can skip all that opening and checking of libraries and interfaces.
Happy programming!
John Mc Keown
Thank-you very much for these programming posts. I’m a returning Amiga-user and a hope-to-be-programmer.
On your advice I downloaded the CubicIDE demo and it looks very nice. It was easy to compile a simple little cli program I had written.
If I may be so bold … perhaps you could post your 2 entries on Libraries over on OS4Coding.net — it would be nice to have as much quality reference as possible in one place.
I’m current on a 3.9 UAE set-up, but hope to join the AmigaOS4.2 band-wagon next year. It’s hard to know how to cross from plain ANSI-C into the deep waters of AmigaOS programming. Nice-and-easy articles like this are a joy for me — much more attractive than reading through the RKM manuals and then finding out there are new OS4-specific ways to do things.
Once again, thank-you!!
Coder
Thanks John!
I have no problems getting my stuff posted on OS4Coding.net Learned a lot from it myself from stuff over there.
As long as the documentation is there and good it is not very difficult. For example ReAction, very difficult to grasp but after reading the articles on OS4Coding.net I started to get a really good understanding of it. Documentation is so important. I don’t mind finding things on my own but some things cannot be found at all or if you do are very difficult to understand. I gave up so many times but always started again.Today I will start again with something I had binned because of lack of info but after some of Trixie’s stuff I am going to start with it again.
AlfaRomeo
Very good stuff here..
There are in the net too much generic C tutorials but Amiga specific C tutorials there are only few and none so good as this one.
Congratulations for your tutorials and many thanks for trying to help us understand how to program our beloved Amiga
Coder
My pleasure. 🙂 It’s comments like these that keep me going.