Aros/Developer/Porting software

From Wikibooks, open books for an open world
Jump to: navigation, search
Navbar for the Aros wikibook
Aros User Docs
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
68k Support
PPC Power Architecture Support
Arm Raspberry Pi Support
Android support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Aros x86 Installing
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros x86 Complete System HCL
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
misc
Aros Public License


Introduction[edit]

Before 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)

  • Acceptable: ANSI-C/C++, SDL, GTK via gtk-mui, Cairo (old port), OpenGL via Gallium3D acceleration, ...
  • Very difficult: PyGame, Boost, Allegro, no SDL, Gnome, KDE and/or QT4, etc.
  • Impossible: Java, C#, any Windows only source, etc.


Compilers and tools[edit]

Open 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[edit]

Open 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 various options available. You'll need time to look over 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 or ask questions here.



EDITING CONFIGURE to suit AROS[edit]

Take 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[edit]

Generic template makefile (not to be used)[edit]

which 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[edit]

Just use the one that suits you.

#Simpler version sufficient 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)/*~ 



Hints for correcting errors[edit]

Forum post and see here and here Be warned that these links apply to using Linux to compile code and not native but may be useful.

Undefs about AROSMesa mean -lgl, undefs about sdl_wav mean -lsdl_mixer, undefs about std:: and operators mean that you need to use or g++ , or if you use gcc, then add to -lstdc++.

Link order are 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 

Additionally, most AROS code depends on the library bases being opened automagically 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.


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...[edit]

AmigaOS[edit]

The 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 end with _proto.h

#include <dos/dos_proto.h>
to
#include <proto/dos.h>

and if you want it more portable than 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 comiler 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>



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. Many things are 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 deprecated and you are advised to convert its calls to use workbench.library/OpenWorkbenchObject() (which should be a pretty easy job).

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[edit]

As 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[edit]

Some 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'll almost certainly fail).
  • Endianess 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 endianess. There are C #define macros to handle writing/reading the correct endianess 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[edit]

Amiga 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[edit]

AmigaOS 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[edit]

Gadtools[edit]

The 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[edit]

MUI - 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[edit]

ReAction/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[edit]

bgui 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[edit]

GCC/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[edit]

SAS/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 not much 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 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[edit]
Dice C[edit]
North C[edit]
  • RAWKEY: replaced with IDCMP_RAWKEY:
  • ModifyIDCMP(win,FLAGSON) replace with ?



MorphOS[edit]

Assemblers/ Disassemblers[edit]

ADis, 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[edit]

On 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[edit]

SDL_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 troubles, 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 intial 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[edit]

Code 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[edit]

A 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 dispacher 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[edit]

Casts 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[edit]

from

make 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 1st one 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[edit]

See here for a tutorial

SDL/MesaGL/OpenGL game frameworks. Jumpcore Minimal

Tutorial

Amiga Tetris

Irrlicht 3D engine