Aros/Developer/Porting software
Introduction
editBefore you attempt to port a program, make sure it's API dependencies are met on AROS. (AmigaOS (TM) 3.x C API is considered AROS native)
Compilers and tools
editOpen shell - its a menu option at the top left of Wanderer (desktop). Or by using the right Win key and w (or F12 and w) within the directory with the makefile. Type in
sh
to change the amiga shell into a unix shell. You can then type in ls (unix equivalent to amiga dir). Take a look here for commands.
For a single file program-name.c or program-name.cpp
gcc -o program-name program-name.c
or
g++ -o program-name program-name.cpp
To close the shell, click on the top left-hand corner to close (twice).
Other missing symbols are due to linker libraries being necessary for linking in functions that aren't in the standard C libraries. For example some source code would need added
-lz -lm -lpng
to compile or even -lmui switch to link a program with a MUI gui.
use this in unix line command mode to search for 'search-item' in many .c files (*.cpp for c++, etc.)
grep -l 'search-item' *.c
Using CONFIGURE to create a Makefile
editOpen shell - its a menu option at the top left of Wanderer (desktop). Or by using the right Win key and w within the directory with the configure and make files. Type in
sh
to change the amiga shell into a unix shell.
configure—help
to see the available options. You'll need time to examine the options and choose the right ones. Hints are available later on. When you configure GCC using the `configure' script, it will construct the file `Makefile' from the template file `Makefile.in'. When it does this, it will incorporate makefile fragment files from the `config' directory, named `t-TARGET' and `x-HOST'. If these files do not exist, it means nothing needs to be added for a given target or host.
Examples...
configure prefix=/PROGDIR --build=i686 --host=i686 --disable-nls configure prefix=/PROGDIR --build=i386 --host=i386 --disable-nls --without-opengl --without-star --disable-sdltest configure LDFLAGS="-nix" --prefix=/PROGDIR --build=i386 --disable-nls --without-x --without-pic --disable-shared GREP=bin: --enable-client=sdl --disable-server --disable-sdltest --with-sdl-prefix=development:include/SDL
to create a Makefile but if it does not work, look at the Hints section below
EDITING CONFIGURE to suit AROS
editTake a look at Fishy's tutorial first
dir ../ unix moving back a directory or two
dir / amiga equivalent
When the Makefile is created, whilst in the unix shell, type in
make -f Makefile
to create the program...
CREATING MAKEFILE from a blank text file
editGeneric template makefile (not to be used)
editwhich requires multiple copies of .c .o files
CC = gcc #CC = g++ #AS = nasm -f coff #AR = ar LDFLAGS = -s FLAGS = -I. -Icpu -Iaros -Wall -march=pentium -fomit-frame-pointer LIBS = -lz -lm -LDevelopment:lib #LIBS = -lSDL_net lSDL_ttf -lSDL_mixer -lSDL_image -lpng -ljpeg -lz -lvorbisfile -logg -lSDL #LIBS = -lz -lm -LDevelopment:lib -lglu -lglut -lgl -lSDL_mixer -lSDL_image -lpng -ljpeg -lz -lSDL EXE = name OPTS = -O2 # @echo "Building source files..." $(CC) $(FLAGS) $(OPTS) -c src/.c -o obj/.o $(CC) $(FLAGS) $(OPTS) -c src/.c -o obj/.o #$(CC) $(FLAGS) $(OPTS) -c src/.cpp -o obj/.o #$(CC) $(FLAGS) $(OPTS) -c src/.cpp -o obj/.o @echo "Making executable..." $(CC) $(LDFLAGS) $(FLAGS) -o $(EXE) obj/.o $(LIBS) @echo "Done!"
Remove # from CC = g++, if g++ compiler needed. Remember to put # it in front of CC = gcc. # at the start acts as a comment line and are not processed. Similarly, remove/add # in the LIBS part to activate simple command line compiling, simple SDL compiling or openGL compiling respectively.
Replace name with the program title in EXE part.
Then add various .c (compiling with gcc) or .cpp (compiling with g++) source code you want to compile and .o also
$(CC) $(FLAGS) $(OPTS) -c src/main.c -o obj/main.o
Finally, collect all the .o for the final line
$(CC) $(LDFLAGS) $(FLAGS) -o $(EXE) obj/main.o main2.o etc.o $(LIBS)
MakeTools should be looked at also.
CC = gcc CFLAGS = -O LDFLAGS = -lSDL_image -lpng -ljpeg -lSDL_ttf -lfreetype2 -lSDL_mixer -lvorbisfile -lvorbis -logg -lSDL -lgl -lglu -lz -lstdc++ -lm OBJS = part1.o part2.o main.o # $(OBJS) will look above for list of .o and then use the statements below to see what to do with them myprogram: ${OBJS} ${CC} -o myprogram ${CFLAGS} ${OBJS} $(LDFLAGS) #-------------------------------------------------------- part1.o: part1.c part1.h header.h ${CC} ${CFLAGS} -c part1.c part2.o: part2.c header.h ${CC} ${CFLAGS} -c part2.c main.o: main.c header.h ${CC} ${CFLAGS} -c main.c clean: rm -f myprogram ${OBJS} @echo "all cleaned up!"
Better Makefiles
editJust use the one that suits you.
#Simpler version suffices for most small-scale projects #DEPS is needed to recompile hellomake.c with changed hellomake.h CC=gcc CFLAGS=-I. DEPS = hellomake.h # gcc, $(CC) and rm need to be TABbed to work with make # macro DEPS, which is the set of .h files on which the .c files depend %.o: %.c $(DEPS) # -o $@ compiler output into file named on the left side of hellomake: below ie hellomake # the $< is the first item in the dependencies list #DEPS $(CC) -c -o $@ $< $(CFLAGS) #putting the object files--hellomake.o and hellofunc.o in dependency list #make knows it must first compile the .c versions individually, and then build the executable hellomake hellomake: hellomake.o hellofunc.o gcc -o hellomake hellomake.o hellofunc.o -I
CC = gcc CFLAGS = -O2 -I/include LDFLAGS = -lSDL_image -lpng -ljpeg -lSDL_ttf -lfreetype2 -lSDL_mixer -lvorbisfile -lvorbis -logg -lSDL -lgl -lglu -lz -lstdc++ -lm #----------------------------------------------------------------------------- OBJS = part1.o main.o program: $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) $(STRIP) --strip-unneeded --remove-section=.comment $@ #----------------------------------------------------------------------------- part1.o: part1.c part1.h @echo " Compiling $*..." @$(CC) $(CFLAGS) $*.c main.o: main.c header.h @echo " Compiling $*..." @${CC} ${CFLAGS} $*.c clean: rm -f myprogram ${OBJS} @echo "all cleaned up!"
# Template for a simple generic Makefile # CC = i386-aros-gcc # CPP = i386-aros-gcc -E # CXX = # CPPFLAGS = # CXXFLAGS = CFLAGS = (cflags) LDFLAGS = (ldflags) TARGET = (final-file-name) OBJECTS = file1.o file2.o file3.o LINKS = file1.c file2.c file3.c # XTRAOBJ = # # rules # all: $(TARGET) $(TARGET): $(OBJECTS) $(XTRAOBJ) $(CC) $(OBJECTS) $(XTRAOBJ) $(LDFLAGS) -o $(TARGET) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ # # eof # Cycloid Makefile Example # OBJ = window2.o # # w.exe: $(OBJ) # $(CC) $(CFLAGS) -o $@ $^ $(ARCHIVE) $(LIB) # # window.o: window2.c # # $(CC) $(INCL) -c window2.c
# .h files in an include directory IDIR =../include CC=gcc CFLAGS=-I$(IDIR) # .o files into a obj subdirectory and some local libraries in lib directory ODIR=obj LDIR =../lib macro defined for any libraries you want to include, like mui library -lMUI LIBS=-lMUI _DEPS = hellomake.h DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) _OBJ = hellomake.o hellofunc.o OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) $(ODIR)/%.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) hellomake: $(OBJ) gcc -o $@ $^ $(CFLAGS) $(LIBS) # .PHONY rule keeps make from doing something with a file named clean .PHONY: clean # cleaning up your source and object directories clean: rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
#simple makefile CC=gcc CFLAGS=-O2 -s -DNO_INLINE_STDARG -I./api/ -I../api/ -I../modules/api/ -I../amide/modules/api/amide/ LDFLAGS=$(CFLAGS) -nostartfiles -nodefaultlibs -lamiga -lstdc.static -lgcc EXE=plugins/test.plugin # Objects OBJS = StartUp.o \ LibInit.o \ sasc_module.o all: $(EXE) clean: rm -f *.o $(EXE) $(EXE): $(OBJS) echo Making $@.. $(CC) -o $(EXE) $(OBJS) $(LDFLAGS)
Hints for correcting errors
edit- undefs about std:: and operators mean that you need to use or g++ , or if you use gcc, then add to -lstdc++
- undefs about sdl_wav mean -lsdl_mixer,
- undefs about AROSMesa mean -lgl,
Link order is important, so you can't for example firstly do -lgl, and then -lsdl. As sdl wants gl, you will need to do -lsdl -lgl, and the same for all the other libs : include one after another when undefs happens.
-lSDL_image -lpng -ljpeg -lSDL_ttf -lfreetype2 -lSDL_mixer -lvorbisfile -lvorbis -logg -lSDL -lgl -lglu -lz -lstdc++ -lm
There are undefined symbols in 'sasc.module': __PROGRAM_ENTRIES__symbol_set_handler_missing __LIBS__symbol_set_handler_missing
remove the -nostartfiles argument from command line the missing symbols are part of AROS automatic startup handling. Possibly manually adding -llibinit could fix the missing symbols.
add -nodefaultlibs like this:
LINK := $(OPTIMIZE) -s -nostartfiles -nodefaultlibs
should remove all automatically added libraries and now you will have to add them manually
$(CC) $(LINK) -o $@ $(O_FILES) -lamiga -lstdc.static -lgcc
#simple makefile CC=gcc CFLAGS=-O2 -s -DNO_INLINE_STDARG -I./api/ -I../api/ -I../modules/api/ -I../amide/modules/api/amide/ LDFLAGS=$(CFLAGS) -nostartfiles -nodefaultlibs -lamiga -lstdc.static -lgcc EXE=plugins/test.plugin # Objects OBJS = StartUp.o \ LibInit.o \ sasc_module.o all: $(EXE) clean: rm -f *.o $(EXE) $(EXE): $(OBJS) echo Making $@.. $(CC) -o $(EXE) $(OBJS) $(LDFLAGS)
and LoadModules function calls that function from main.c, case of AROS it is best to use portable macros to make these calls
mod_class =AROS_LC0(void *, AmIDE_API_GetClass, struct Library *, (AmIDE_API_Base), 5, AmIDE_API );
- include <aros/libcall.h>
Additionally, most AROS code depends on the library bases being opened automatically so you may need to add a link library, libauto (-lauto). Some systems (so it's down to the compiler to provide it) don't have working libauto in which case you need to open the library bases manually.
Hints can be found here Be warned that these links apply to using Linux to compile code and not native but may be useful.
CONFIGURE ERRORS Error : no acceptable C compiler found in $PATH Solution : add CC=gcc or CC=g++ after configure Error : no acceptable grep could be found in /Development/bin: Solution : add GREP=bin: to configure line Error : gtk-mui library sequence Solution : gcc -o test addbutton.c\ -lglib-2.0 -lgtlayout -lgthread-2.0 -lgmodule-2.0 -lgobject-2.0 -lgtk-mui -lglib-2.o -liconv -lmui -lthread Error : VARIABLE not within scope Solution : add headers like... #include <libraries/mui.h> #include <proto/muimaster.h> or #include <string.h> etc Error : malloc.h no such file or directory Solution : malloc is contained within <aros/stdlib.h> Error : SDL.h no such file or directory Solution : #include SDL/SDL.h needed at top of .c file or -IDevelopment:include/SDL to the command line Error : Solution : Error : IMG_Load in -lSDL_image ... cannot find libSDL_image Solution : ?? Error : pow in -lm - 'case' unmatched - math.library (-lm) appears broken Solution : ?? Error : Solution : Error : Solution : MAKE ERRORS Error : *** missing separator. Stop. Solution : Make commands like gcc $(CC) or rm need to be TABbed in and not use spaces Error : Solution : Error : Solution : Error : Solution : COMPILING ERRORS Error : expected '=' ';' "asm" or '__attribute__' before '{' Solution : look at previous lines for missing/extra ; (like in defines) or missing } or forgot to #include something.h. Use gcc -E to check Error : request for member 'something' in function not a structure or union Solution : using b.x = 12 (usually arrays); when it should be b->x (usually structs) or (*b).x, .h needed, Error : 'something' undeclared (first use in this function) Solution : 'something' been declared at start of function, .h needed or link library needed -lmui etc., Error : there are undefined symbols in program Solution : /* around these symbols' */ until you work out if they are needed or can be deleted Error : there are undefined symbols in <program-name> or memcpy strndup first Solution : linker library not included -lz -lSDL or -lGL etc or <string.h> Error : expected specifier-qualifier list before 'USHORT' Solution : change all references of USHORT into UWORD (SHORT into WORD) Error : expected declaration specifiers or '...' before 'USHORT' Solution : replace USHORT with UWORD (SHORT into WORD) Error : field 'name' has incomplete type Solution : Error : expected ')' before 'type' Solution : Error : invalid conversion from 'ULONG*' to 'IPTR*' Solution : most amiga like OS's return ULONG values or use ULONG TAGS but 64bit AROS needs IPTR used for compatibility Error : dereferencing pointer to incomplete type Solution : Error : If crackly break-up noise found in SDL sound Solution : try to find where the number of samples for the buffer is set in the source and increase it (double it at least). This solves many sound issues with SDL programs. The buffer was set to 1024, now set it to 4096. Error : initializer element is not constant around TAG_DONE); Solution : header(s) <utility.h> and <proto/utility.h> need to be added Error : no i386-sdl-config Solution : use --build=i686 instead of --build=i386 Error : functions not found at final linking: SDL_CondWait, SDL_CondSignal, SDL_CreateCond Solution : find them in the SDL_cond_aros.c file in the cdxlplay-sdl source http://www.a500.org/downloads/video/ Error : crash glutGet((GLenum)GLUT_ELAPSED_TIME); Solution : The glutInit function is needed, replace with by SDL_GetTicks() Error : undefined symbols: recv, connect, inet_pton, socket, select, send, inet_ntoa Solution : LDFLAGS : -lSDL_net -lSDL with #include <proto/bsdsocket.h> (or <proto/socket.h>) in all files using SDL_net Error : SDL is not built with CDROM support. Solution : Look for SDL_INIT. It can look something like this: if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) change it to: if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK ) == -1 ) That includes all the init routines available in SDL, minus the CD one. Error : Video mode set failed: OpenGL support not configured Solution : 'sdl-config --libs' is fine for most SDL uses, but with GL it needs to be replaced with "-lgl" Error : Solution : Error : Solution : RUN TIME ERRORS Error : Solution : Error : Solution : Error : Solution : Error : Solution : Error : Solution : Delinting (removing warning messages) 64bit compatibility - MUIA_Application_Copyright, _(MSG_AppCopyright), + MUIA_Application_Copyright, (IPTR)_(MSG_AppCopyright), - io->io_Unit = (struct Unit *)unitnum; + io->io_Unit = (struct Unit *)(IPTR)unitnum; Clean up - ULONG signals; + ULONG signals = 0; - while((t = LibNextTagItem(&tagList))) + while((t = LibNextTagItem((struct TagItem **)&tagList))) - while ((tag = LibNextTagItem(&msg))) + while ((tag = LibNextTagItem((struct TagItem **)&msg))) - const struct TagItem *tstate = msg->ops_AttrList; - struct TagItem *tag; + struct TagItem *tag, *tstate = msg->ops_AttrList; - sprintf(buf, "SYS/printer%d.prefs", unit); + sprintf(buf, "SYS/printer%d.prefs", (int)unit); - STRPTR _return = NULL; + CONST_STRPTR _return = NULL; - return (CONST_STRPTR)_return; + return _return;
Hints: Porting software from...
editAmigaOS
editThe right form of the main() function is
int main(void) { ... return retval; } or int main(int argc, char **argv) { ... return retval; }
(Old code has often "void main()" or no return type at all)
For retval you can either use 0, EXIT_SUCCESS or EXIT_FAILURE (ANSI-C) or ADOS return codes which I don't know off-hand.
First turn anything that ending in _proto.h
#include <dos/dos_proto.h> to #include <proto/dos.h>
and if you want it more portable, then try
#ifdef AROS #include <proto/dos.h> #else #include <dos/dos_proto.h> #endif
Include function prototypes for shared libraries from proto e.g. #include <proto/graphics.h> instead of #include <clib/graphics_protos.h>
If the compiler complains about wrong type in a line like
struct Library *GfxBase
you have to look up the right type in the header, e.g. in includes/proto/graphics.h
#include <proto/library_name.h>
(replacing with correct name) should pull in the necessary info for automatic opening/closing of CORE libraries to work with basic applications which are written as DOS and Workbench/Wanderer launched processes. Others like mui have to be specified (-lmui in the gcc command line).
It looks like you are still including from clib. You either have to include from proto or you have to link with -lexec -lgadtools, etc.
There are undefined symbols in 'inctst': U AllocMem U FreeMem
Adding -lexec removed the errors.
There are undefined symbols in 'a.out': SetFont CloseFont OpenFont
try -lgraphics or #include <proto/graphics.h> or #include <defines/graphics.h> or #include <clib/graphics_protos.h>
Include sys/types.h before netinet/ip.h Include <netdb.h> first before rest of your network includes
Most AROS C/C++ Compilers can open and close the libraries for you as part of the startup code. As long as you have the protos included in the headers and the appropriate compiler options specified, the compiler will take care of opening any used libraries for you.
The library header source is in principle like AOS 68k too, with Resident struct, functable and so on. Except AROS has its own set of macros for functions which get parameters in registers. The AROS_LH#? and AROS_UFH#? stuff. You should be able to use contrib/mui/classes/nlist/commonaros/mccheader.c from AROS contrib sources as a hint.
But always remember, that coding for AROS is not coding for m68k Amiga. Much is different here and coding AROS in C means searching hundreds of include files for macros. And AROS source code is partly useless for an external newbie developer, as AROS has a deeply integrated build system which hides important parts from the implementing developers, e.g. a shared library consists only of its methods, the rest (Romtag, Jumptable etc.) is hidden in the AROS build system.
wbstart.library isn't ported indeed but its usage is depreciated and you are advised to convert its calls to use workbench.library/OpenWorkbenchObject() (which should be easy).
A temporary quick trick is to use CLI callings on C:Open which will launch programs using Workbench (using this very function). It can even be used with arguments which are passed as workbench arguments (ie like multi-clicked files).
Programming languages
editAs long as no assembler code is being used in the program, compiling a C program written for plain AmigaOS up to version 3.1 should be possible on AROS without any changes to the source code. (That presumes your AROS is using a 32bit big-endian CPU, like the original Amiga computer.) (Please note that AROS is still beta and incomplete, and might lack some functions from AmigaOS API. See Status of AROS implementation for more on this.)
Data types and sizes / little endian / big endian
editSome of the first things to consider is the actual size of your C data types, and in your uses of binary files (IFF for example) paying attention to reading and writing with portability to 64bit and little-endian CPUs as well as the classic mc680x0 or powerpc cpus used by Amiga OS.
- Warning signs is casting between char * and WORD/LONG/short/int etc., or any kind of pointer arithmetic, as well as any functions that read/write binary file formats (if they read character by character and/or does things similar to what I mentioned above, they are likely to be ok, if they read a chunk of memory in and treat it as a struct immediately then it will almost certainly fail).
- Endianness issues need to be fixed and there are a lot of them (reading/writing binary files, writing data into graphics frame buffers). Also network stack, file system, hardware. Pretty much any time you have to deal with external data, you have to worry about endianness. There are C #define macros to handle writing/reading the correct endianness and flipping the ordering when necessary.
- all LONG/ULONG/APTRs need to be checked if they need to be replaced by IPTR (e.g. relying on TagLists)
[we should probably have a chart showing sizes/endian used by Manx/sas/dice C on a mc68000/68030 vs today's PPC/i386/x86_64 AROS options here along with some GCC source code to show how to read/write binary files correctly under AROS running on differing endian CPUs]
Screens
editAmiga chipset-graphics-based screens were generally done in a planar format 16/32-colors max for ECS hires/lores modes respectively and 256-colors for AGA.
[a chart of common amiga screen modes should go here]
Methods that worked well for the relatively low-resolution planar Amiga displays may be suboptimal for chunky and true color screens that are common today.
[pointer to examples should go here]
Amiga screens could be of differing resolution, which could be dragged up and down to reveal another, so some applications were written with differing resolution screens, say for a control panel at one resolution and another for the "display" visible at the same time stacked vertically. This may not make sense with today's chip sets or wide-screen displays. Opening multiple screens that vary in scan rate can confuse displays (monitors or projectors) that might take several seconds "calibrating" every time the user decides to change which public or private application screen they want to view. Defaulting to the user's preference for Wanderer (workbench) for screen mode is probably better than having a predefined mode hard-coded into your application.
Fonts
editAmigaOS 3.1 also shipped with some nice disk fonts that are not currently available under AROS, so you should be careful about having any diskfont hard-coded as a default into your program. The ROM font "topaz" should be ok.
AROS fonts (as of 2010-03-10):
- arial.font
- dejavusansbold.font
- dejavusansboldoblique.font
- dejavusansbook.font
- dejavusanscondensedbold.font
- dejavusanscondensedboldobl.font
- dejavusanscondensedcondens.font
- dejavusanscondensedoblique.font
- dejavusansextralight.font
- dejavusansmonobold.font
- dejavusansmonoboldoblique.font
- dejavusansmonobook.font
- dejavusansmonooblique.font
- dejavusansoblique.font
- dejavuserifbold.font
- dejavuserifboldoblique.font
- dejavuserifbook.font
- dejavuserifcondensedbold.font
- dejavuserifcondensedboldob.font
- dejavuserifcondensedconden.font
- dejavuserifcondensedobliqu.font
- dejavuserifoblique.font
- fixed.font
- stop.font
- ttcourier.font
- Vera Mono Bold.font
- Vera Mono Bold Italic.font
- Vera Mono.font
- Vera Mono Italic.font
- Vera Sans Bold.font
- Vera Sans Bold Italic.font
- Vera Sans.font
- Vera Sans Italic.font
- Vera Serif Bold.font
- Vera Serif.font
- XEN.font
GUI Toolkits
editGadtools
editThe order of the fields in struct Node which is currently different than on AOS (will be changed in ABI V1).
struct Node has currently the following order:
struct Node { struct Node * ln_Succ, * ln_Pred; char * ln_Name; UBYTE ln_Type; BYTE ln_Pri; };
MUI
editMUI - AROS' preferred GUI toolkit is Zune, a reimplementation of MUI 3.x, thus MUI 3.x code will work unchanged under AROS. MUI 4.x will need adapting or wait for the following bounty to be started.
ClassAct
editReAction/ClassAct, a GUI toolkit for AmigaOS, is not available for AROS. It has been made part of AmigaOS 3.5 and higher. Programs that use ReAction might need considerable rework, preferably to use Zune (or: MUI), AROS' GUI toolkit.
BGui
editbgui is available as part of the "contrib" archive, thus included in all current AROS binary distributions.
[We could use a chart comparing gui options for developers here.]
C/C++ Compilers
editGCC/G++ is the primary C compiler supplied with AROS. Amiga programs making use of other compilers' (SAS/C, Maxon C, ...) specific functionality might need some rework. You'll probably want to write makefiles that can run either hosted or native, so any AROS user can get them compiled and running on their machine. In a hosted environment the shell will most likely use UNIX semantics like cp==COPY ../==parent directory, and all file names will be case sensitive for your makefile and inside your C source code files (example: #include "myFile.h" != #include "MyFile.H"). Under AROS the makefile may use Amiga shell command semantics (copy #? progdir:prefs)or it may be using a UNIX shell ported to AROS, and the AROS environment, and like AmigaOS 3.1 may not care about case sensitivity of file names.
We can't use the SLOWSTACKTAGS macros for getting ULONG values from a variadic list.
SAS Lattice C Compiler
editSAS/C was one of the more popular compiler packages back when AmigaOS 3.1 was released, it supported various keywords such as __chip for using chipram, and CPU-related register arguments that the current AROS GCC does not.
The makefiles will have to be translated from SMAKE to GNU Make and some of the headers will have to be translated from SC to GCC.
Pragmas were used on ancient C compilers like SASC. Include from "proto", e.g. #include <proto/workbench.h>. Look if there are headers which include from "clib". Change them to "proto", too.
You can ignore warnings like "suggested parentheses..." or incompatible pointer types.
Some types and names of defines have changed (SHORT/USHORT -> WORD/UWORD).
-linput -lutility -lintuition -lrexxsyslib -lconsole -lgraphics -ldos -lexec
strmfp, stcgfe, stcgfp, stcgfn and stci_d are SAS/C / Lattice function that do not exist under gcc. They have to be reimplemented.
tolower and toupper was found once I've included ctype.h in the source code. Sometimes missing symbols come from missing include files. Those are macros like toupper—not real functions, and the C preprocessor needs the include definition for the macro.
If you want your characters to be unsigned you need to put unsigned into the variable type. If you want them to be signed, put signed in the variable type. If you don't put either, you may get unexpected results.
Sometimes you need wrappers for functions which aren't part of ANSI C.
SAS/C allowed to use a type before it was defined => change the order or use forward declaration.
Use AROS macros for Hook functions as explained here: http://aros.sourceforge.net/documentation/developers/app-dev/portable.php#hooks
There might be more if you are porting system software (libraries, interrupts etc.) Just start and try to find the reason for warnings and errors.
Generally when porting sources, if a header doesn't exist in AROS, wrap it with an #if or #ifndef statement and see what symbols, structure definitions, etc. aren't found. Then you can look through the AROS includes to see if the missing symbols, etc. are implemented in another place, or if you have to make your own compatible include file with those defined.
For libraries you might want to look at the AROS source-tree to see how others have done it using things like sfdc, genmodule, etc.
- SAS/C included a ton of non-standard functions in its C library. Alternative versions of these can generally be found online, and for example YAM includes some of them in their sources, depending on license working around this is easy (none of these functions are big/difficult to re-implement if needed).
- SAS/C is very liberal in some of the things it accepts. This causes problems particularly for vbcc (not so relevant for AROS) but some things also for gcc, particularly in terms of type coercion and (lack) of forward declarations.
- SAS/C has a multitude of extensions targeting AmigaOS, such as non-standard 68k focused register declarations. These must either be removed or worked around by defining preprocessor macros that expand to nothing or a suitable replacement.
- The SAS/C smakefiles are a totally non-standard syntax.
- The general caveats of AmigaOS vs. AROS include files apply - many paths can be expected to be different.
- there might be endian issues
- you'll get a lot of compiler warnings. Some of them are harmless (e.g. "parenthesis suggested ..."). Others are dangerous (e.g. "variable xxx may be undefined")
- for some specials like callback hooks you'll have to use AROS macros.
- Use texteditor or some tool to replace all "ULONG" with "IPTR" and "LONG" with "SIPTR" in the sources.
- Fix (change IPTR/SIPTR back to ULONG/LONG) the few places which really rely on ULONG/LONG being exactly 32 bit. That's for things like pixel (ARGB) buffers, structs written/read to disk, colormaps, but probably little else.
This is the code that I use in diskimage.device for converting a BSTR to a CSTR
LONG CopyStringBSTRToC (BSTR src, STRPTR dst, ULONG dst_size) { #ifdef __AROS__ STRPTR ptr = AROS_BSTR_ADDR(src); ULONG ln = AROS_BSTR_strlen(src); #else UBYTE *ptr = BADDR(src); ULONG ln = *ptr++; #endif if (ln > (dst_size-1)) ln = dst_size-1; memcpy(dst, ptr, ln); dst[ln] = 0; return ln; }
Some blankers[check spelling] are missing the symbol "custom". They have (as documented in the OS3.9 RKM) "extern struct Custom custom;". 'Custom' is a struct that maps the m68k Amiga AGA/OCS/ECS registers. Only build those for amiga-m68k, and you'll be fine.
Maxon Hisoft C
editDice C
editNorth C
edit- RAWKEY: replaced with IDCMP_RAWKEY:
- ModifyIDCMP(win,FLAGSON) replace with ?
MorphOS
editAssemblers/ Disassemblers
editADis, which reads binaries into memory hunk by hunk to disassemble them, and then just treats it as an array of short. The "right" way would be to treat it as a char *, and do (arr[0] << 8) + arr[1]. I wanted to use it to cross-disassemble M68k programs, but gave up and went with Ira instead because it was so pervasive.
Linux Console Apps
editOn AmigaOS this is done by libc on every I/O operation. Just AROS libs lacks this. Resources allocated by libc (malloc()ed memory, fopen() ed files, etc.) are safely reclaimed at exit(). libc tracks this internally. If your program additionally uses some AmigaOS API, it usually installs exit handler (I don't remebmer how), or disables Ctrl-C checking by redefining __chkabort() function.
You have to explicitly check for it on AROS (and AmigaOS). The reason for this is that there's no safe way for the OS to kill an app and reclaim all resources on AmigaOS and derivatives (since an app can have "handed off" memory and other resources to other tasks).
This is an example from the autodocs for SetSignal:
#include <libraries/dos.h> /* Check & clear CTRL_C signal */ if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { printf("CTRL-C pressed!n"); }
It is compiler dependent. It's safer to just do the SetSignal()-based check.
If you want a shared library, recommend getting linux-hosted aros building (use the gimmearos.sh script) and then look at the other library sources found in AROS/workbench/libs for examples of how its done.
If it were just a linker library, you can just compile the .c files with -fno-stack-protector (needed under aros-sdk cross compiler under linux, native aros gcc might not need that), etc. and join the .o files into a lib-yournamehere.a file with ar and ranlib them.
SDL
editSDL_image may need -ljpeg -lpng -lz
SDL_mixer needs -lSDL_mixer -lvorbisfile -lvorbis -logg (in this order)
First thing to test with SDL sound under AROS is to increase the buffer. In all applications had needed this to obtain good sound output.
In most cases it would certainly mean that you have to increase the value of SYSSND_MIXSAMPLES. Usually multiplying this value by 2 or 4 gives good results.
You should also check the value of the obtained structure. It is not sure that AROS supports AUDIO_U8 and you might have reverted to AUDIO_U16. In this case sound will of course be distorted.
from here
Further tests with buffers using code from here, and this is the result I've noted:
"a quick test compiling with 1024, 2048 or 4096 gave interesting results: 1024 - sounds are more responsive to key-events but if you quickly move the "game-window" around the screen you can hear sound glitches. 2048 - No big difference noticed in responsiveness and now no glitches moving the window around, anyway the fx-sound sample plays with some hiss-click glitches. 4096 - No hiss-click and no glitches moving the window BUT you can see that the responsiveness is decreased.
Trying this code then with original xRick 8bit samples gives good sound results, and even using 1024 bytes buffer the sound doesn't glitch when moving window"
Seems to me that buffer depends a lot on responsiveness you need, overall game load and also what kind of sound samples you're using (of course the lower is the bit-encoding and frequency, the smaller you can use as buffer).
SDL_GetTicks just disable
m_fLastTime = float(SDL_GetTicks())/1000;
in 2 places of sdlapp.cpp and add your own code at the end:
Ellapsed_Time = SDL_GetTicks() - Last_Time; if (Ellapsed_Time < 20) /* 20 ms target => 50FPS */ { SDL_Delay(20 - Ellapsed_Time); }
Maybe SDL_GetTicks works a bit wrong by some reasons in aros's SDL, right ? (because if the same code works fast on os4/mos/win32/anything-else), then it mean that something wrong with SDL_GetTicks then .. PS : SDL_GetTicks() isn't causing any trouble, its a basic SDL function that is used in almost all SDL applications.
int CSDLApplication::Run() in sdlapp.cpp
and
bool CMySDLApplication::FrameMove() in Armygaem.cpp
In initial-code Render3DEnvironment is called continuously and only FrameMove is updated at 50fps, Render() and SDL_GL_SwapBuffers() are called even if nothing has moved. Calling the render() functions and SDL_GL_SwapBuffers(), too often is for me the root cause. A correction to OpenGL implementation would only be a safeguard to prevent stupid application from crashing or slowing down the system.
crash on exit is certainly due to the application not freeing any resources before exiting.
Writing ROM-able code
editCode in AROS modules should be written in a way that makes it suitable for embedding into a ROM, FlashRAM or other kinds read-only memory. The following coding style rules are meant to make it possible. Of course they apply to all Kickstart modules and to code that may be made resident, shared or linked to other modules.
ROM modules must have no .data and .bss sections. Basically, we need to get rid of all non-const global data. The real Amiga Kickstart proves that it's both possible and easy to achieve this. If you encounter an external variable (static or not) that is modified by the code, try to get rid of it or move it into the base of the library/device (or in the device node of your handler or in the userdata of your class).
The above applies to library bases as well. If you are writing a library, put the bases of other libraries into your own library base structure. Boopsi classes can store library bases in their class private data.
Try to set the static and const attributes to all your global data. You can also use the CONST_STRPTR and CONST_APTR types defined in <exec/types.h>. Using static const allows the compiler to move data into the .text (AKA code) segment. If you need to pass these globals to another function, try to change its prototype to use const too.
Hooks and SDI
editA hook is a custom function you write in order to be able to handle a specific situation that arises from intercepting the main code (like processing a message). The function must be designed to accept three arguments, whose order and type is given.
- the first parameter (A0) contains the pointer to your hook, not to your window
- the 2nd Parameter points to the Object which causes this action, this isn´t your window but it´s the Object which was pressed (it´s always the Object which was connected to the Hook (=1st Parameter of DoMethod)
- then give 5 as number of Parameters for MUIM_CallHook, but´s 4 (=number of all Parameters in DoMethod after the Count Parameter)
AROS_UFH3S ( void, MyHookFunction, AROS_UFHA(struct Hook * , hook, A0), AROS_UFHA(Object * , obj, A2), AROS_UFHA(ULONG * , params, A1) )
params is an array but IPTR should be correct. Then you can access your parameters...
app = (Object *) *params++; window2 = (Object *) params++;
The important thing about hook functions is that the parameters must be given in the order A0, A2, A1. And not to leave out parameters even if they are unused by the hook function. For initial quick&dirty ports one can even simply defines things like "__saveds", "__asm", "__regargs", "__stdargs", "register ..." to nothing. For library functions it's the same (with library base as last param). InitLib: libbase(d0), seglist(a0), sysbase(a6) OpenLib: version(d0), libbase(a6) CloseLib: libbase(a6) ExpungeLib: libbase(d0), libbase(a6) OpenDev: ioreq(A1), unitnum(d0), flags(d1), devbase(a6) CloseDev: ioreq(a1), devbase(a6)
see here
The AROS asm call and lib call macros require param type (like "struct Hook *") and param (like "myhook") to be passed in two different arguments. Not in a single one.
Converting is easy. Adding some "AROS_" prefix plus some commas. Additionally in the hook functions and dispatcher functions "HOOK_INIT" / "HOOK_EXIT" / "DISPATCHER_INIT" / "DISPATCHER_EXIT" must be used (in case of AROS mapping to AROS_USERFUNC_INIT/AROS_USERFUNC_EXIT).
To force procedure parameters to use registers (like a0) in GCC
Since C calling convention on some machines (like 68k or x86) means params are passed on stack your C function must have params in correct order (Hook, object, msg) and not leave out params if they are unused by the function especially if it's the middle param (object).
ULONG hook_function(REG(a0, struct Hook *hook), REG(a2, APTR object), REG(a1, APTR message))
In short when using HookEntry you initialize hooks like this:
STATIC ULONG hookfunc(struct Hook *hook, APTR obj, APTR msg) { /* ... *// } #if defined(__amigaos4__) hook->h_Entry = hookfunc; #else hook->h_Entry = &HookEntry; hook->h_SubEntry = hookfunc #endif
If you are not using SDI headers this is the most universal method which works on OS3, OS4, AROS and MorphOS with every compiler and architecture.
Those dispatchers are usually taken as argument for MUI_CreateCustomClass(), which has:
#if defined(__MAXON__) || defined(__amigaos4__) cl->cl_Dispatcher.h_Entry = (HOOKFUNC)dispatcher; #else cl->cl_Dispatcher.h_Entry = (HOOKFUNC)metaDispatcher; cl->cl_Dispatcher.h_SubEntry = (HOOKFUNC)dispatcher; #endif
metaDispatcher:
#ifdef __AROS__ AROS_UFH3(IPTR, metaDispatcher, AROS_UFHA(struct IClass *, cl, A0), AROS_UFHA(Object *, obj, A2), AROS_UFHA(Msg , msg, A1)) { AROS_USERFUNC_INIT return AROS_UFC4(IPTR, cl->cl_Dispatcher.h_SubEntry, AROS_UFPA(Class *, cl, A0), AROS_UFPA(Object *, obj, A2), AROS_UFPA(Msg , msg, A1), AROS_UFPA(APTR , cl->cl_Dispatcher.h_Data, A6) ); AROS_USERFUNC_EXIT }
What confuses me is that our own macros have registers:
#define BOOPSI_DISPATCHER(rettype,name,cl,obj,msg) \ AROS_UFH3(SAVEDS rettype, name,\ AROS_UFHA(Class *, cl, A0),\ AROS_UFHA(Object *, obj, A2),\ AROS_UFHA(Msg , msg, A1)) {AROS_USERFUNC_INIT
Maybe there is a difference between MUI and BOOPSI when it comes to dispatchers and SDI DISPATCHER can only be used for MUI.
AROS's MUI_CreateCustomClass() moves the dispatcher to h_SubEntry and uses something like HookEntry for h_Entry. There we don't have to care about registers.
BTW: SDI's hook macros *are* wrong for AROS.
HOOKPROTONHNO(TestFunc, void, int *param) { puts("Foobar"); } MakeHook(TestHook, TestFunc);
expands to:
static void TestFunc(__attribute__((unused)) struct Hook *_hook, __attribute__((unused)) APTR _obj, int *param) { puts("Foobar"); } struct Hook TestHook = {{0L, 0L}, (HOOKFUNC)TestFunc, NULL, 0L};
That works only by accident on i386-AROS (because of stack parameters). But there I *know* how to fix it and will soon send an update to you.
#elif __AROS__ #define MakeHook(hookname, funcname) struct Hook hookname = {{NULL, NULL}, \ (HOOKFUNC)HookEntry, (HOOKFUNC)funcname, NULL} #define MakeHookWithData(hookname, funcname, data) struct Hook hookname = \ {{NULL, NULL}, (HOOKFUNC)HookEntry, (HOOKFUNC)funcname, (APTR)data} #define MakeStaticHook(hookname, funcname) static struct Hook hookname = \ {{NULL, NULL}, (HOOKFUNC)HookEntry, (HOOKFUNC)funcname, NULL} #define ENTRY(func) (APTR)func #define DISPATCHERPROTO(name) SAVEDS ASM IPTR name(REG(a0, \ struct IClass * cl), REG(a2, Object * obj), REG(a1, Msg msg)) #define DISPATCHER(name) DISPATCHERPROTO(name) #define SDISPATCHER(name) static DISPATCHERPROTO(name)
Difference is that funcname is moved to h_SubEntry. Problem are the dispatcher macros. They'll currently only work with MUI_CreateCustomClass(). If I define them like our BOOPSI macros I have a new problem: what happens if I define a function with register macros
- AND* use HookEntry in h_Entry and the function in h_SubEntry?
BTW: in SDI_compiler.h there is:
/* we have to distinguish between AmigaOS4 and MorphOS */ #if defined(_M68000) || defined(__M68000) || defined(__mc68000) #define REG(reg,arg) arg __asm(#reg) #define LREG(reg,arg) register REG(reg,arg) #else #define REG(reg,arg) arg #define SAVEDS
C++ is much more strict on types than C, this is the root of the problem. Absolutely everything should be casted, implicit conversions are not allowed at all. P.S. And casting is considered an extremely bad coding style IIRC...
Those who want to develop AROS API in C++ should update their headers from a current SDK.
HOOKFUNC looks now like this in include/utility/hooks.h:
typedef IPTR (*HOOKFUNC)();
The prototypes have been included in "extern C" blocks, so that problems like this should be gone
Casts
editCasts simply put... casting through pointers, bad... casting through a union, good*. (*exceptions apply) Hopefully someone can correct me if I'm wrong, but the main rule of thumb for avoiding these problems seems to be to not have two pointer variables in the same function that point to the same memory, but are of different type.
It's actually a little more subtle than this. They can point to different types, but not when the types do not contain sub-sets of the others.
i.e.
struct Foo { struct MinNode Node; };
- any cast from struct Foo * to struct MinNode * is ok ... but:
struct Foo { struct Foo *next; struct Foo *prev; };
- now casts from 'foo' to 'minnode' are not ok ... and worse, can be silently discarded (how that is considered polite behaviour I do not know). (and by extension, casting from List to Node are right out).
I would argue that this is actually a different language - it is no longer 'C', as such, and although the spec (as far as I have been able to ascertain) actually specifies this it has never been implemented in such a way until now. It is there to provide additional optimisation opportunities ... although the whole 'we'll just silently drop code that is otherwise quite obvious' thing is rather nasty.
The CellPerformance stuff really nails it all. Although I find it somewhat absurd you can cast pretty much anything through a union and it's 'ok', but using the language 'cast' exactly the same physical operation becomes 'illegal'.
NEVER EVER touch buffers passed in by the user as an "input" parameter. The concept of input parameters is often implicit in the function description. For instance, the filename passed to Open() is clearly an input variable and Open() must not mess with it, even if it is going to fix it back later. Keep in mind that the buffer might be in read-only memory or shared among several instances of a resident or multithreaded program.
Try to avoid host-OS calls such as malloc() and free() if you can do with AllocMem() and FreeMem(). This is because the pointer checking debug macros rely on finding the pointer within the Exec memory blocks with TypeOfMem().
SA_BackFill, (ULONG) &sbackfillhook,
Please do not use ULONG's to store/cast pointers in your code. use APTR/IPTR where appropriate.
Compiling small parts of AROS source without using Build system
editmake stub make make install
and need genmodule from inside here.
Trying to build the support modules of Ignition with a normal Makefile:
How can I get rid of these linker warnings? U __includelibrarieshandling and U __this_program_requires_symbol_sets_handling
Is there something I have to care about when I create a module this way?
(I have always used the build system in the past) Is there a function which must be the first in the generated module?
Are you using ld directly? If so, don't do that, use the compiler's driver instead (gcc, that is) to do all the steps, final linking included. The problem arises because the linker needs to be invoked through a wrapper, which in our case is called collect-aros (it would be collect2 on other systems). You can either call collect-aros in place of ld (I wouldn't do that) or the compiler's driver (gcc, do that) as said above. Mh, hadn't noticed the makefile when I first replied and I had forgotten these symbols are actually produced by collect-aros itself.
The problem arises because you are using -nostartfiles, which avoids linking with the startup file, but the startup file contains code that handles the automatic libraries opening/closing and the generic symbol sets handling. By using DFLAGS=-lgraphics -lintuition -lutility you are actually linking with stub libraries that require the automatic handling of shared libraries to be implemented. Either you avoid using these stubs or you implement the needed code yourself. You can take inspiration from the normal startup code.
After re-enabling lines like
#define UtilityBase cb->UtilityBase
I was able to build the module without the stub libraries.
Tutorials
editSee here for a tutorial
SDL/MesaGL/OpenGL game frameworks. Jumpcore Minimal