peter@cbmvax.commodore.com (Peter Cherna) (12/16/89)
In article <1989Dec15.042112.9582@aucs.uucp> 840445m@aucs.UUCP (Alan McKay) writes: >In article <596@cameron.cs.duke.edu> amr@dukee.egr.duke.edu (Anthony M. Richardson) writes: >>I've always thought the Amiga shared libraries were a nifty idea and >>so I've decided to try and create my own library. Blink (with thei >> >>Tony Richardson amr@dukee.egr.duke.edu > >Try 'oml' which comes with Lattice 5.0x. It is used specifically for >making shared libraries. >-- >+ Alan W. McKay + VOICE: (902) 542-1565 + >+ Acadia University + "Courage my friend, it is not yet too late + >+ WOLFVILLE, N.S. + to make the world a better place." + >+ 840445m@AcadiaU.CA + - Tommy Douglas + Actually, oml is for making linked libraries, which may indeed by shared _at_compile_time_. Things like lc.lib, amiga.lib, and others are like this. However, I believe Anthony is talking about making Amiga shared libraries that live in libs:. There are new support features as of the 5.04 release of Lattice that help make this easy. Your C source modules must be compiled with the -ml switch. If you have a function foo that takes an int and a long *, and returns a char *, you would declare it like char * __saveds __asm LIB_foo(register __d0 int i, register __a0 long *lptr) The __saveds instructs Lattice to set up your data area (off A4) when anybody calls your function. The __asm keyword states that you intend to specify which registers receive which parameters, as shown above. The 'LIB_' is any prefix you care to associate with the actual names of the functions. You must also provide this prefix to blink. If you wish from within your library to call one of your public functions through the function table, you just do so, as in: cptr = foo(i, lptr) In highly exceptional circumstances, you may wish to call yourself directly (not through the table). Then use cptr = LIB_foo(i, lptr) Note that if someone SetFunctions() your library, only the former type of call are affected. You will also have to create an "fd" file, which typically looks like ##base MyLibBase ##bias 30 foo(i,lptr)(D0/A0) ... ##end The ##base directive names the library base that clients of your library will need. The ##bias directive gives the offset to the first of your functions (for a library, it is 30). Your functions follow, with the parameters named in brackets, and the registers after. Registers are separated by "/" or by ",". Use "/" when in correct order for multiple moves (An/Am or Dn/Dm are ok if n < m, An/Dm is always ok, Dm with An must use a comma, i.e. Dm,An). Lattice's fd2pragma utility will build a pragma file you can include so that clients may call your routines. They'll have to declare struct Library *MyLibBase and call OpenLibrary() to get it. The declaration must precede the #include of your pragma file. In order to call yourself through the library jump table, you must also include this file. Your own library base will be in A6, so you should #define MyLibBase (struct Library *)getreg(REG_A6) When you link, you must link with Lattice's libent.o first, libinit.c second, and your .o files after. As well, you provide LIBPREFIX _LIB_ (or whatever you chose, but you'll need a leading underscore here), and LIBFD mylib.fd (your fd file). Also, you may use what look like global variables, and Lattice arranges to stuff them off your library base. In the source to libinit.c, they imply you can initialize stuff at the appropriate moment. Well, a warning: DO NOT INITIALIZE ANY OF YOUR GLOBALS IN LIBINIT.C. If you need to do stuff upon open, add a call to some MyOpenFunc() inside LibOpen(), and put that function in a module other than libinit.c. If you need stuff in your library base to be public, you'll have to extend the MyLibrary structure in libinit.c, and figure out how to access it. Any globals that Lattice cares for you automatically are placed whereever Lattice feels, and could change as you change your source. You should end up with a shared library. Hope this helps. -- Peter Cherna, Software Engineer, Commodore-Amiga, Inc. {uunet|rutgers}!cbmvax!peter peter@cbmvax.cbm.commodore.com My opinions do not necessarily represent the opinions of my employer. "A friend of mine is into Voodoo Acupuncture. You don't have to go. You'll just be walking down the street and ..... oooohhh, that's much better..." - Steven Wright
ggk@tirith.UUCP (Gregory Kritsch) (09/16/90)
In a message posted on 16 Sep 90 15:55:29 GMT, butch@fergvax.unl.edu (FERGVAX Daily Operator) wrote: FDO> Anyway, if anyone who has made a library for the Amiga and would FDO>not mind sharing the how-to's of it all, I would very much appreciate FDO>it, since I've tried and failed on several occasions to make one. Okay, I've created several libraries successfully, and so I may as well try to document what I've done. I use Lattice C 5.05, and Lattice Asm for my work. I do NOT use the blink library making utility, since it does not work as far as I can tell. There are some things which must be done awkwardly, I'd be interested in hearing of anyone's solutions. The first part of creating a library is the first segment of the load file, which pretty much has to be done with an assembler (to get data in the code section). I'm going to insert an example file, and add documentation to each step along the way. All files , comments, and notes in this example are copyright (c) 1990 by Gregory Kritsch, All rights reserved, except where borrowed from the v1.1 RKM Appendix library example, which is copyright (c) 1985 Commodore-Amiga Inc. By now, the amount of actual Commodore code is so minimal, I don't think this really matters. Use as an example basis for freeware products is permitted. EMail me (ggk@tirith.UUCP) for details on using it in a commercial or shareware product. * * $Header: tirith:usr/dev/work/juliet/jms/rcs/lib.a,v 2.0 90/04/01 15:35:30 kritschg Exp $ * include "base.i" That file describes a few constants, and includes all the other files. See below. csect romtag,0,2,0,4 ; code segment ; long word aligned ; use 4 byte absolute addresses The RomTag must occur in the first HUNK_CODE segment in the load module. Assigning it a unique section name and not using Small Code is probably a good idea (don't let the linker merge it, just in case it moves it). The closer you can get the RomTag to the beginning of the segment, the (almost trivially) faster it will be found. ;--- external references ;--- standard library vectors xref _LibInit xref _LibOpen xref _LibClose xref _LibExpunge xref _LibNull These functions are written in C. If you're doing assembly, they should probably go in this segment as well. These are the "standard" library functions... the next set are "custom". Yes, the table was derived from the _lib.fd file - remember, third column is comments. I've added two '_', rather than one for a reason. It allows me to call my own library internally through #pragmas and the library base rather than directly. This means that SetFunction() will be fully, not partially, effective. ;--- custom function vectors xref __ARexxQuery () () xref ___mblog (fmt,a,b,c,d,e) (A0,D0/D1/D2/D3/D4) xref __AddFlo (name,mode) (A0,D0) xref __AddReq (file,pass) (A0,A1) xref __FindScreen ()() xref __FreeScreen ()() xref __SetScreen (scr)(a0) xref __AddArea (area) (A0) xref __OpenArea (name,mode) (A0,D0) xref __OpenFirstArea (mode) (D0) xref __OpenNextArea (area,mode) (A0,D0) xref __CloseArea (area) (A0) xref __RemoveArea (area) (A0) xref __ReadMsg (area,num,msg,text) (A0,D0,A1,A2) xref __ReadMsgText (area,num,msg,text) (A0,D0,A1,A2) xref __UpdateMsg (area,num,msg) (A0,D0,A1) xref __PostMsg (area,msg,text) (A0,A1,A2) xref __DeleteMsg (area,num) (A0,D0) xref __GetField (body,field,buf,len) (A0,A1,A2,D0) xref __FindField (body,name)(A0,A1) ;--- debugging IFD DEBUG xref _dprintf ENDC The debugging at this level essentially causes register dumps on every function call entry and exit. There's not much else. Oh, btw, I'm using lattice's __asm keyword, so my arguments are passed to the C functions in registers, not on the stack. If you want (need) them on the stack, you must put assembler stubs inside the library, or you could specify that your functions take parameters on the stack (unlike nearly every other library out there). ;--- beginning of the code ; if called from AmigaDOS, return error code 30 entry: moveq.l #30,d0 rts Really simple. Set d0 to some value and RTS, in case the user types your library name in as a command. The RKM reccomends 0, I use 30 here to cause a failure. Once I wrote a short routine to print out the library idString (see below) and return. This is the romtag. Notice that it is, uh, 4 bytes (I think) from the beginning of the segment. Look in the file exec/resident.{h|i} for the details on this structure. Be very careful not to mess it up. ;--- romtag and other resident stuff romtag: dc.w RTC_MATCHWORD dc.l romtag The first six bytes identify the RomTag. The first two bytes MUST be RTC_MATCHWORD (which is "the official illegal instruction"), and the following long word MUST be a pointer to the first byte. dc.l endskip This pointer MUST be within the same segment, according to the RKM. I'm not entirely sure why, but I suspect it has to do with searching and not finding an appropriate library (like if someone renames the .library file). dc.b RTF_AUTOINIT There are two bits defined for that field, RTF_COLDSTART and RTF_AUTOINIT. RTF_COLDSTART is for libraries in the ROM or on the KickTagPtr list, and indicates they should be inited during boot time. Otherwise, I think they would be inited on the first OpenLibrary() call for them, but I'm not sure. The second is RTF_AUTOINIT. Since a RomTag can indicate just about anything, not just a library or device, you don't always want Exec to create a Library base structure for you. By setting RTF_AUTOINIT, the RT_INIT field points to a four long word structure used to create the library base. Otherwise, it points to a function to execute to initialize the whatever. Some older libraries and devices don't use RTF_AUTOINIT, and create the library base internally. dc.b VERSION dc.b NT_LIBRARY Oh, by the way, with the assistance of the RKM, you can also use this template to create an NT_DEVICE entry (just add two more standard functions, BeginIO and AbortIO). Or, if you want to put some code or something on the KickTagPtr list, you can set this to something else. dc.b 0 That was the priority. Only really used if you're on the KickTagPtr list (or in the ROMs). dc.l libname dc.l libid libname is a nul terminated string, including the ".library". It must exactly match the disk file name, except in case sensitivity. Note that OpenLibrary() IS case sensitive. libid is the "idString" of your library. It has a very rigid format in the RKM: 'name version.revision (dd MMM yyyy)',13,10,0 I don't know of anything that depends on this, but you should follow it anyhow. dc.l init This is the RT_INIT pointer discussed in RTF_AUTOINIT. Immediately following is the init table. init: dc.l BaseSize The POSITIVE size of your library base, AT LEAST sizeof(struct Library). If you have extended your library structure to include private data, you should MAKE SURE you use the correct size. I have an external program that basically does a printf("%d\n",sizeof(struct JulietBase)). THIS IS WHERE A MESSUP WILL HURT! dc.l LibFuncTab A pointer to an array of function entry points, terminated by a -1 (see below). dc.l LibDataTab A pointer to an InitStruct data array. See the autodocs on exec/InitStruct() if you're curious, exec/initializers.i is enough info to build the table I think. dc.l LibInit A pointer to an init function to call. ;--- function table LibFuncTab: ;--- standard functions ;--- debug trap versions IFD DEBUG dc.l LibOpen dc.l LibClose dc.l LibExpunge dc.l LibNull ENDC ;--- non-debug trap versions IFND DEBUG dc.l _LibOpen dc.l _LibClose dc.l LibExpunge dc.l _LibNull ENDC ;--- custom functions dc.l __ARexxQuery () () dc.l ___mblog (fmt,a,b,c,d,e) (A0,D0/D1/D2/D3/D4) dc.l __AddFlo (name,mode) (A0,D0) dc.l __AddReq (file,pass) (A0,A1) dc.l __FindScreen ()() dc.l __FreeScreen ()() dc.l __SetScreen (scr)(a0) dc.l __AddArea (area) (A0) dc.l __OpenArea (name,mode) (A0,D0) dc.l __OpenFirstArea (mode) (D0) dc.l __OpenNextArea (area,mode) (A0,D0) dc.l __CloseArea (area) (A0) dc.l __RemoveArea (area) (A0) dc.l ReadMsg (area,num,msg,text) (A0,D0,A1,A2) dc.l ReadMsgText (area,num,msg,text) (A0,D0,A1,A2) dc.l __UpdateMsg (area,msg) (A0,A1) dc.l PostMsg (area,msg,text) (A0,A1,A2) dc.l __DeleteMsg (area,num) (A0,D0) dc.l GetField (body,field,buf,len) (A0,A1,A2,D0) dc.l __FindField (body,field) (A0,A1) dc.l -1 ;--- data to initialize the library base with LibDataTab: INITBYTE LH_TYPE,NT_LIBRARY INITLONG LN_NAME,libname INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED INITWORD LIB_VERSION,VERSION INITWORD LIB_REVISION,REVISION INITLONG LIB_IDSTRING,libid dc.l 0 Most of LibDataTab is probably directly from the RKM, since I don't claim to fully understand InitStruct() [yet]. Probably doing a straight copy is your safest bet. ;--- the name and id strings libname: dc.b 'jms.library',0 libid: dc.b 'JMS II (12 May 1990)',13,10,0 Note the nul terminated strings. You should change them to suit your own needs. ;--- word align for code ds.l 0 The following "functions" are mainly to correct problems I had. Some of them may not have been neccesary, I'm not sure. It works, I'm happy. LibInit: movem.l d1-d7/a0-a6,-(sp) jsr _LibInit movem.l (sp)+,d1-d7/a0-a6 rts the LibInit function has a return value in d0. Everything else must be preserved I think, including A0,A1,D1 (which normally aren't). As noted below, there is (was?) a bug in Lattice 5.04, where using the __asm key with too many registers caused it to clobber some before taking working copies. I wish Lattice was a bit more intelligent with the __asm keyword. ;--- kludge aroung LC 5.04 compiler errors with __asm keyword ; passing A0,A1,A2 and A6 results in A2 being clobbered ReadMsg: move.l a2,d1 jmp __ReadMsg ReadMsgText: move.l a2,d1 jmp __ReadMsgText PostMsg: move.l a2,d1 jmp __PostMsg GetField: move.l a2,d1 jmp __GetField ;--- kludge to preserve registers properly for expunge routine IFND DEBUG LibExpunge: movem.l a0-a6/d1-d7,-(sp) jsr _LibExpunge movem.l (sp)+,a0-a6/d1-d7 rts ENDC The debugging traps exist for the register dump. It does, however, look like I've removed that code partially from this lib.a version. ;--- debugging traps IFD DEBUG LibOpen: jsr _LibOpen rts LibClose: jmp _LibClose LibExpunge: bsr regdump movem.l a0-a6/d1-d7,-(sp) jsr _LibExpunge movem.l (sp)+,a0-a6/d1-d7 bsr regdump rts LibNull: jmp _LibNull regdump: bchg #1,$bfe001 movem.l d0-d7/a0-a7,-(sp) pea fmtstr jsr _dprintf For the curious, dprintf() is a Lattice function that goes directly to the printer, through the cia port and the debug.lib RawDoFmt() type functions. move.l #14965,d0 1$ dbra d0,1$ addq.l #4,sp movem.l (sp)+,d0-d7/a0-a7 bchg #1,$bfe001 rts fmtstr: dc.b 'd0:$%08lx d1:$%08lx d2:$%08lx d3:$%08lx',13,10 dc.b 'd4:$%08lx d5:$%08lx d6:$%08lx d7:$%08lx',13,10 dc.b 'a0:$%08lx a1:$%08lx a2:$%08lx a3:$%08lx',13,10 dc.b 'a4:$%08lx a5:$%08lx a6:$%08lx a7:$%08lx',13,10 dc.b 13,10,0 ENDC ;--- align the endskip ds.l 0 ;--- end of this segment endskip: endskip MUST MUST MUST be in the same segment as the RomTag. end -- end of lib.a -- Now, base.i, for the curious. Fairly boring. BaseSize is determined by an external program, of course. ;------------------------------------ ; $Header: tirith:usr/dev/work/juliet/jms/rcs/base.i,v 2.0 90/04/01 15:44:50 kritschg Exp $ ; $Author: kritschg $ ; $Revision: 2.0 $ ; $Date: 90/04/01 15:44:50 $ ;------------------------------------ include "exec/types.i" include "exec/libraries.i" include "exec/lists.i" include "exec/resident.i" include "exec/initializers.i" BaseSize equ $000008D4 VERSION equ 2 REVISION equ 0 SUBREV equ 0 -- end of base.i -- Now, library.c. This is the C functions for LibOpen, LibClose, LibInit, LibExpunge, and LibNull. There are some strange things in here, that aren't explained very well in the RKM docs. I'm cutting parts of this file out, that are directly related to the discussion of creating a library. /* * $Header: tirith:usr/dev/work/juliet/jms/rcs/library.c,v 2.0 90/04/01 15:35:51 kritschg Exp $ */ #include "jms/jms.h" Note that struct JulietBase is defined in jms/jms.h. It's not really important, other than it begins as: struct JulietBase { struct Library Library; ULONG SegList; The struct Library MUST be the first field in the structure, this is the only restriction. For no apparent reason, you are passed your library base pointer in d0 and the result of LoadSeg() in a0. Every other library function has the library base in A6. Remember, this is assuming RTF_AUTOINIT. If you don't use RTF_AUTOINIT, I'm not sure what you get (if anything at all). Note: Exec has, I think, done a Forbid() for you here, and will call Permit() later for you. The RKM reccomends keeping this routine very short. I tend to agree. Return Value: You should return the pointer to your library base (or NULL if the init failed), in D0 (which is the normal register for Lattice C to put return values in). struct JulietBase * __asm LibInit(register __d0 unsigned long lb, register __a0 unsigned long Seglist) { register struct JulietBase *JulietBase; JulietBase = (struct JulietBase *)lb; JulietBase->Seglist = Seglist; return(JulietBase); } This function is called when Exec has determined that it needs some memory, typically from within AllocMem() when there is very little memory available. As such, MAKE NO ASSUMPTIONS about the context you will be called in. You may be a Task or a Process, so dos calls are probably out. Calling AllocMem() is probably taboo as well. Note: Once again, Exec has called Forbid() for you, and will call Permit() for you as well. Keep it short and sweet. Note: The RKM infers that Expunge will be called by AllocMem() whenever it needs memory. My experience is that it will only be called by AllocMem() IF THE OPENCNT IS 0. I hope CBM fixes this (sometimes, Expunge could free data structures not in use, even though the library is open). Return Value: Return a NULL if your library is still in memory, or the segment list (stored somewhere from the LibInit call) if you wish to be unloaded. long __asm LibExpunge(register __a6 struct JulietBase *JulietBase) { long seg; register struct Area *area, *next; /* now expunge the library if possible */ if (JulietBase->Library.lib_OpenCnt == 0) { Remove(JulietBase); As soon as you call Remove, you're off the library list, and that pretty much gaurantees that you'll want to return your seglist and be removed from memory. Any conditions should be checked BEFORE THIS POINT. seg = JulietBase->Seglist; FreeMem((void *)(((long)JulietBase) - JulietBase->Library.lib_NegSize),JulietBase->Library.lib_NegSize + JulietBase->Library.lib_PosSize); NOTE: YOU MUST CACHE THE SEGMENT LIST BEFORE CALLING FREEMEM(). As soon as you call FreeMem(), the library base is considered entirely invalid. return(seg); } else { JulietBase->Library.lib_Flags |= LIBF_DELEXP; I'm not 100% sure, but the RKM has this clause, so I have it too. I don't think I've ever seen it called (I don't think it can be). However, if you have your own conditionals about expunges, you should set LIBF_DELEXP if Expunge is called and you don't remove yourself. return(NULL); } } This is called by the OpenLibrary() function every time someone opens the library. I think Exec does a Forbid(), but its definitely not as critical. I do dos calls here. Note: Increment the open count, and clear the LIBF_DELEXP bit in this function. Return Value: return the library base pointer. struct JulietBase * __asm LibOpen(register __a6 struct JulietBase *JulietBase) { JulietBase->Library.lib_OpenCnt++; JulietBase->Library.lib_Flags &= ~LIBF_DELEXP; return(JulietBase); } This is related to a call to CloseLibrary(). There are two possible results from this function: a NULL, which means to just keep on going, or the segment list, which means that you've called expunge and it returned the seglist, indicating the library should be removed. The CloseLibrary() call to LibExpunge() is done IF LIBF_DELEXP is set. Note: Decrement the open count. long __asm LibClose( register __a6 struct JulietBase *JulietBase, register __a1 struct IOStdReq *ior) { JulietBase->Library.lib_OpenCnt--; /* determine if we should try to expunge */ if ((JulietBase->Library.lib_OpenCnt == 0) && (JulietBase->Library.lib_Flags & LIBF_DELEXP)) { return(LibExpunge(JulietBase)); } else { return(NULL); } } This is sort of a "reserved for future expansion" function. It should return NULL, I think (either that or just be an rts), so this code below may be wrong. I don't think it will be called under 1.3, although maybe under 2.0... void __asm LibNull() { } -- end of library.c -- Additional notes: When compiling, I use lc1 -b0 to force absolute addressing. Needless to say, A4 will not be properly set for relative addressing. There is no c.o, so getting A4 might also be some fun. I think the lc2 -y may work, but I'm note sure. Specify the lib.a object module FIRST on the FROM line to BLink. Be careful using SMALLCODE and/or SMALLDATA. Don't link with any of the c*.o family. Also remember that since there is NO c.o, so some things just plain won't work properly. You should stay away from any complicated runtime library functions (like C files), and should use pragmas for external libraries. Avoid amiga.lib like the plague, I only include it for the dprintf() function. Note that the best thing for other libraries (like dos, graphics, intuition, &c) is to add struct MumbleBase *MumbleBase to your library base structure, and create your own #pragma files using YourBase->MumbleBase as the library base (instead of the Lattice provided #pragmas, which use the global MumbleBase). Globals aren't actually evil, just strongly disreccommended. Remember, if you use globals, especially if they're volatile (ie they change) you should put semaphores around access to them. Even stuff in your library base may need to be semaphored. Remember that you CAN have the very same function doing the very same thing at almost the very same time within library code. Declare your library base for all functions. An example declaration: /* * $Header: Bottom:usr/dev/work/juliet/msg/rcs/field.c,v 2.0 90/04/01 18:05:49 kritschg Exp $ */ #include "jms/jms.h" char * __asm _FindField(register __a6 struct JulietBase *JulietBase, register __a0 char *body, register __a1 char *name) { Note that this function could call itself recursively as FindField(), not _FindField(), if you include the normal pragmas to your own library. This has the advantage that SetFunction() works for calls made inside your library (which is a good idea). Oh, a word about .fd files. They're really simple: ##base <base name> * this is a comment: <base name> must start with an '_' for fd2pragma, * this _ is removed (normal C vs. Asm thing). * eg. ##base _JulietBase ##bias 30 * the offset of the first function, expressed as a positive rather than * a negative. Just leave it at 30. function(arg1,arg2,...)(r1,r2,...) * argN are not actually looked at, but make them meaniful for humans * reading the file. * rN are one of the registers D0-D7/A0-A5 (A6 and A7 are already in use). ##end * you MUST mark the end this way If you have any questions, mail me. FDO>Butch Rosecrans FDO>butch@fergvax.unl.edu --- Gregory Kritsch Fido: 1:221/208.11110 [1:163/109.30] UUCP: xenitec!tirith!ggk
lphillips@lpami.wimsey.bc.ca (Larry Phillips) (09/16/90)
In <2751.653532429@tirith.UUCP>, ggk@tirith.UUCP (Gregory Kritsch) writes: > >Okay, I've created several libraries successfully, and so I may as well >try to document what I've done. > Very nice tutorial Gregory! Thanks for the posting. -larry -- It is not possible to both understand and appreciate Intel CPUs. -D.Wolfskill +-----------------------------------------------------------------------+ | // Larry Phillips | | \X/ lphillips@lpami.wimsey.bc.ca -or- uunet!van-bc!lpami!lphillips | | COMPUSERVE: 76703,4322 -or- 76703.4322@compuserve.com | +-----------------------------------------------------------------------+
butch@fergvax.unl.edu (FERGVAX Daily Operator) (09/16/90)
I posted a message about a month or so ago asking for any help making a shared library for the Amiga. I got a few responses from people pointing to other sources, but none of those ever helped (I never got a response about the Amiga Developer's Newsletter which supposedly had an article on the subject). Anyway, if anyone who has made a library for the Amiga and would not mind sharing the how-to's of it all, I would very much appreciate it, since I've tried and failed on several occasions to make one. Also, if anyone has a copy of the Developer's Newsletter which has the article on making libraries, I would be interested in getting a copy (if it doesn't violate any copyright laws). I'm not a develop so I don't suppose I can subscribe to the newsletter (if non-developers can subscribe, please let me know how). Thanks in advance for any info, Butch Rosecrans butch@fergvax.unl.edu
lhotka@incstar.uucp (Glamdring) (09/17/90)
In article <butch.653500529@fergvax>, butch@fergvax.unl.edu (FERGVAX Daily Operator) writes: > Anyway, if anyone who has made a library for the Amiga and would > not mind sharing the how-to's of it all, I would very much appreciate > it, since I've tried and failed on several occasions to make one. I would second this motion - if anyone would like to post an example or some pointers on this topic it would be very nice. I have read through several books and such, but it is still somewhat confusing and no one ever seems to publish an example... > Butch Rosecrans > butch@fergvax.unl.edu ______________________________________________________________________ / Rockford Lhotka INCSTAR Corp \ | Systems Administrator PO Box 285 | | incstar!lhotka@rosevax.rosemount.com 1990 Industrial Blvd | \ 612/779-1701 Stillwater, MN 55082 / ----------------------------------------------------------------------
dlarson@blake.u.washington.edu (Dale Larson) (09/18/90)
>In article <butch.653500529@fergvax>, butch@fergvax.unl.edu (FERGVAX Daily Operator) writes: >> Anyway, if anyone who has made a library for the Amiga and would >> not mind sharing the how-to's of it all, I would very much appreciate >> it, since I've tried and failed on several occasions to make one. Manx comes with example code and detailed instructions for the creation and use of shared libraries. Under 5.0 it is really easy. -- -Dale Larson (dlarson@blake.u.washington.edu)
valentin@cbmvax.commodore.com (Valentin Pepelea) (09/21/90)
In article <259@incstar.uucp> lhotka@incstar.uucp (Glamdring) writes: > >> Anyway, if anyone who has made a library for the Amiga and would >> not mind sharing the how-to's of it all, I would very much appreciate >> it, since I've tried and failed on several occasions to make one. > > I would second this motion - if anyone would like to post an example or > some pointers on this topic it would be very nice. I have read through > several books and such, but it is still somewhat confusing and no one ever > seems to publish an example... You both have pointed out a weakness in the available documentation. While the useage of shared libraries and devices is well explained, the process of creating such beasts is covered with clarity and simplicity exemplified by the KGB documentation bureau. All I can do to help you out for now, it to tell you that there is nothing to it. Shared libraries consist simply of a skeleton, along with a set of functions that accompany them. For an assembler example, look in the ROM Kernel Manual, Includes & Autodocs. For a C example, look in AmigaMail, page III-11. AmigaMail is a tachnical newsletter sent by CATS (Commodore-Amiga Technical Support) to registered devellopers. No, I don't work for CATS. Valentin -- The Goddess of democracy? "The tyrants Name: Valentin Pepelea may distroy a statue, but they cannot Phone: (215) 431-9327 kill a god." UseNet: cbmvax!valentin@uunet.uu.net - Ancient Chinese Proverb Claimer: I not Commodore spokesman be
bcphyagi@Twg-S5.uucp (Stephen Walton) (09/22/90)
In article <14576@cbmvax.commodore.com> valentin@cbmvax.commodore.com (Valentin Pepelea) writes: > >For a C example [of a shared library], look in AmigaMail, page III-11. >AmigaMail is a tachnical newsletter sent by CATS (Commodore-Amiga Technical >Support) to registered devellopers. The AmigaMail article is Lattice-specific. For a C example for Manx 5.0, look in the directory reslib on the fourth (or maybe third) distribution floppy. Write your subroutines, put their names in a table in the supplied main, run Make with the example makefile, and you're done. The next rev of XPR Kermit (currently under development) uses it with great success. -- Stephen R. Walton, Dept. of Physics and Astronomy, Cal State Northridge I am srw@csun.edu no matter WHAT the stupid From: line says!