![]() |
|||
AROS Application Development ManualAvvertenza This guide has it's last major revision begin November 2006. Changes to the build system after this date will not be reflected in this guide. Building an AROS libraryAnother type of binary often built for AROS is a shared library. First a basic skeleton will be given of how to build a library then some handy extensions are given. Basic library skeletonA shared library is built with the %build_module macro with a line like this: %build_module mmake=MetaTarget modname=mylib modtype=library files=SourceFiles This macro can build different AROS module types like devices, Zune classes, HIDDs, ... but we'll focus here on a shared library and therefor we assume that you specify the modtype=library parameter. The mmake and the files parameter act the same as for the %build_prog macro. Additionally to the meta-target MetaTarget and MetaTarget-quick, also meta-targets MetaTarget-includes, MetaTarget-includes-quick and MetaTarget-linklib are defined. This allows to only build a subset of all the files normally generated. They will most of the time be used to specify dependencies. For building a shared library more information is necessary then given in the %build_module macro. This information is stored in another file that by default is called mylib.conf when modname=mylib is specified. This file can contain a lot of information but we'll give here a minimal example. More information can be found in the reference section of the %build_module macro. Here is an example .conf file: ##begin config version 1.0 ##end config ##begin functionlist void func1(LONG a, LONG b) int func2(char *s, ULONG a) ##end functionlist As you can see this is a file with two sections, each section starting with ##begin sectionname and ending with ##end sectionname. The section config is for providing the information needed by AROS when it wants to use the shared library about the library and for giving options to influence the type of module that will be build. In-depth discussion can be found in the reference section. The functionlist section gives a list of functions that will be included in the library and the list consist of the function prototypes. The order of the list is important because it will determine the place of the function in the lookup table. Also empty lines are important because an empty line in the functionlist will cause an empty slot in the table. Comment lines start with one '#' character and these lines will be ignored and do not give rise to an empty slot in the library's table. If all this information is present and you then execute the command make MetaTarget the following file will be generated ($(AROSDIR) corresponds with the directory for the binary tree):
Using non-standard typesIn the example given above standard C variable type or standard exec types were used for the arguments of the function. If you want to use your own types or types defined in other include files you will need to take extra steps. This can be done in the cdef section as shown in the next example where another include file is used: ##begin config ... ##end config ##begin cdef #include <exec/semaphores.h> ##end cdef ##begin functionlist ... BOOL func3(struct SignalSemaphore *sig) ##end functionlist The lines in the cdef structures are normal C code and they will be part of the generated include files before the library's function prototypes. You could also define your own structure like this:
##begin cdef
struct MyStruct
{
...
};
##end cdef
##begin functionlist
...
int func4(struct MyStruct *sig)
##end functionlist
When doing it this way the structure definition will be part of the generated include files. The recommended way to do it in AROS is to do the definition in a separate header file and then include that header file. One way to do it is to define your own file named libraries/mylib.h with the following contents:
#ifndef __LIBRARIES_MYLIB_H
#define __LIBRARIES_MYLIB_H
struct MyStruct
{
...
};
...
#endif /* __LIBRARIES_MYLIB_H */
This file is then copied as explained in another paragraph and then simply included by the cdef section: ##begin cdef #include <libraries/mylib.h> ##end cdef Functions with m68k register passingThe functions put into the library vector table up to now were regular C functions. In the amiga m68k days the parameters for library functions most of the time were passed in registers and not on the stack. For backwards compatibility you can also define functions where the arguments are passed in m68k registers. When your library is compiled for m68k it will use the specified registers, on other architectures own conventions will be used by either using registers available on that CPU or using stack based argument passing. Defining a function with m68k registers has to be done by adding the registers to the line in the function list and use macros for the header of the function in the source code. The line in the functionlist looks as follows: ##begin functionlist ... ULONG func5(ULONG a, STRPTR b) (D0,A0) ... ##end functionlist And the function in the source code is defined as follows:
AROS_LH2(ULONG, func5,
AROS_LHA(ULONG, a, D0),
AROS_LHA(STRPTR, b, A0),
struct Library *, MylibBase, 9, Mylib
)
{
AROS_LIBFUNC_INIT
...
AROS_LIBFUNC_EXIT
}
This macro has the name AROS_LHn with n the number of arguments passed to the function. The macros has the following arguments:
Using an extended libbaseOn AROS and other amiga-like systems every shared library has a library base. The base of a library contains the vector table and some data about the library used by the OS. It can also be extended with user defined data. This can be done by providing your own C struct for the type of the libbase. There are two config options that let you decide the type of the libbase: ##begin config ... libbasetype struct MyLibIntBase libbasetypeextern struct MyLibBase ... ##end config libbasetype is the type used internal in the library code, this type also decides how much memory is allocated for the libbase. If this type is not given struct Library is taken as default. libbasetypeextern is the type by external programs using your library. If not given also here struct Library is used as the type. Both the internal and the external type have to start with a struct Library structure. If the external type is given the first part of the internal type has to be the same as the external type. For keeping your library backwards compatible one can not change the external type of a library. You can only extend it once you have released a version of your library into the public. The internal type can be changed at will when all internal code of your library is adapted to the changes of the internal library structure. The external type also has be exported to the users of your library. This is the same as the usage of other non-standard types. On the contrary, the internal type oftentimes is not meant to be exported to the users, for this reason a cdefprivate section can be put in the config file. This way the library initialization code has all the information about your internal type without having the internal structure publicly exported. A common convention is to declare your internal structures in mylib_intern.h and then include this in the cdefprivate section. The mylib_intern.h would then include the following code:
struct MyLibIntBase
{
struct Library base;
...
};
And the config file the following section: ... ##begin cdefprivate #include "mylib_intern.h" ##end cdefprivate ... Using a per-opener libbaseUp to now only one libbase would be created for a library. All users who open the library get a pointer to the same library base. Sometimes one wants to have data that is different per opener of the library. This can be done by using a special option in the config section: ##begin config ... options peropenerbase ##end config The use of a base per opener of the library does not make much sense when not using an extended libbase. At the moment also the only way to pass the libbase to the functions of the library is by using m68k register passing. (Development is underway to also be able to get the libbase in library functions using the normal C argument passing). You could also add the libbase as an explicit argument to the function but this is not encouraged. Nota On AROS the need for extended libbases is much less then on classic AmigaOS. On classic AmigaOS it was discouraged to use global variables in the library and to use the libbase for storing variables. On AROS global variables are handled fine so the use of an extended libbase is only needed for using a per-opener libbase. Library initializationSometimes you want to perform initialization when your library is loaded or when it is opened. You can use the same mechanism as for programs through the ADD2INIT and ADD2EXIT as in the next example:
static int InitFunc(void)
{
...
}
static void ExitFunc(void)
{
...
}
ADD2INIT(InitFunc, 0);
ADD2EXIT(ExitFunc, 0);
When you add this code in one of your source files the code in InitFunc will be executed when the library is initialized and the code in ExitFunc when the library is expunged. The return value of InitFunc indicates succes or failure, when it returns a zero (== FALSE) value it indicates a failure to initialize and the library will be unloaded again and not be usable. The ExitFunc may not fail and thus has no return value. Often one wants to initialize part of the libbase and therefor the methods discussed above are not appropriate. For libraries additional ways are available for adding initialization or clean-up code: static int InitFunc(struct Library *lh); ADD2INITLIB(InitFunc, 0); static int ExpungeFunc(struct Library *lh); ADD2EXPUNGELIB(ExpungeFunc, 0); static int OpenFunc(struct Library *lh); ADD2OPENLIB(OpenFunc, 0); static void CloseFunc(struct Library *lh); ADD2CLOSELIB(CloseFunc, 0); The InitFunc function will be called once during initialization and the ExpungeFunc once during expunge of the module. OpenFunc and CloseFunc functions are called resp. everytime the modules is opened or closed. InitFunc, ExpungeFunc and OpenFunc return a value indicating the success of the function. If InitFunc fails the module will be expunged, if OpenFunc fails the opening of the library will fail and if ExpungeFunc fails expunging the library will be delayed. If the latter happens the next time the expunge will be tried all registered functions for expunge will be called again. This means that if more then one function is registered and the second function returns 0, the first function will be called a second time the next time AROS tries to expunge the module. If you implement an ExpungeFunc that can return a 0 you also have to be sure that other ExpungeFuncs may be called more then once. If you look at the ADD2...LIB macros above you can also see that next to the function name there is an extra number. This number indicates the priority to call the function. InitFunc and OpenFunc with a higher number will be called after the ones with a lower number. For CloseFunc and ExpungeFunc the opposite order is used, e.g. higher numbers are called before lower numbers. The number is a signed byte, which means it has to have a value from -127 to 128. Most often this value can be kept at 0. If a per-opener base is used a copy will be made of your libbase every time the module is opened. InitFuncs will be called before the copy so initialization of values in the libbase will be seen by all the openers. OpenFuncs are called after the copy of the libbase and changes made to libbase are thus private to the opener. Copying include filesOften when writing a library extra includes have to be provided that can be included by the programs using your library by using #include <...> in the code. For this purpose a copy_includes macro is available. In the following line the arguments are given for the macro with the default values: %copy_includes mmake=includes-copy includes=$(INCLUDE_FILES) path=. dir= Here follows an explanation of the arguments and after that some examples will be given:
Some examples to make this more clear:
Using non-core libraries in programs or librariesBefore programs or other libraries can use another library that is not part of the core AROS libraries they have to add it to the list of libraries to use by using the uselibs argument for the %build_prog or the build_module macro. So if you want your program to use the mylib library you have to do it like this: %build_prog ... uselibs=mylib For a library it looks the same: %build_module ... uselibs=mylib |
Copyright © 1995-2009, The AROS Development Team. Tutti i diritti riservati. Amiga® č un marchio registrato di Amiga Inc. Tutti i diritti sui marchi vanno ai legittimi proprietari. |