UnixLib: Difference between revisions

From RISC OS
Jump to navigationJump to search
(Note about SCL filename handling, use more relevant example for heap)
(Update how UnixLib socket numbers could be translated to RISC OS raw socket numbers; Stress the API compatibility between UnixLib and SCL and not that this is not binary compatibility.)
Line 22: Line 22:
Often, implicit filename translation isn't enough, and the program will need to do explicit translation. You can achieve this with the __riscosify() and __riscosify_std() functions. You can translate in the other direction with __unixify() and __unixify_std(). In older versions of Unixlib, the function was __uname(), but this is now deprecated and should be avoided. The parameters to these functions are also described in the header file.
Often, implicit filename translation isn't enough, and the program will need to do explicit translation. You can achieve this with the __riscosify() and __riscosify_std() functions. You can translate in the other direction with __unixify() and __unixify_std(). In older versions of Unixlib, the function was __uname(), but this is now deprecated and should be avoided. The parameters to these functions are also described in the header file.


== Socket numbers ==
=== Note about SharedCLibrary ===


Socket numbers returned by UnixLib do not have the same value as the associated RISC OS socket handles. Most of the time this is not of any importance but sometimes you really need the corresponding RISC OS socket handle for the socket number you got from UnixLib's socket() call (e.g. to interface with the SocketWatch module). In such cases, you can do the following:
The SharedCLibrary interface with GCC contains these same functions, but they are off by default, and the use is slightly different. To use these, generally you will want to pass "-D__RISCOSIFY" to the GCC command line.


For GCCSDK 3.x releases:
== Memory Usage ==


#define __UNIXLIB_INTERNALS
Instead of using the stack for its heap, Unixlib programs can use a dynamic area for their heap. The traditional way is to set program$heap to any value. e.g:
#include <unixlib/unix.h>
void
socketwatch_register (int socket)
{
socket = (int)__u->fd[socket].handle;
...


I.e. use the global (and internal) UnixLib resource variable __u.
*set gcc$heap ""


In the GCCSDK 4.1.1 Pre-release 1 release, the __u is no longer available but an internal UnixLib function __unixlib_getdev could be used instead.
There is another way, however. If you create the variable __dynamic_da_name, your program will automatically use dynamic areas, and use a more sensible name. e.g.:


void
const char *__dynamic_da_name = "Mozilla Firefox Heap";
socketwatch_register (int socket)

{
== Differences ==
socket = (int)__unixlib_getdev (socket)
...


In releases after GCCSDK 4.1.1 Pre-release 1, __unixlib_getdev got removed from UnixLib's public API and in the GCCSDK 4.1.2 release, finally a dedicated, stable & public call got foreseen:
Unixlib aims to be as compatible with SharedCLibrary as possible. This means it implements all the same C library calls (as required by ANSI C), and also the RISC OS functions such as _swix(), _kernel_swi(), etc. but there are a few differences worth noting:


#include <unixlib/local.h>
If you use socket functions (built into Unixlib, and with TCPIPLibs or NetLib when using SCL) the socket number you get back has a different meaning. Unixlib gives you an opaque file descriptor, as you'd expect in Unix, but TCPIPLib/Netlib gives you a raw RISC OS socket handle.

This almost never matters, except when you need raw handles such as when using the SocketWatch module. This is the solution employed in Nettle:

#include <stdio.h>
void
#ifdef __UNIXLIB_TYPES_H
socketwatch_register(int socket)
#define __UNIXLIB_INTERNALS
#include <unixlib/unix.h>
#endif
void socketwatch_register(int socket)
{
{
socket = __get_ro_socket (socket);
#ifdef __UNIXLIB_TYPES_H
socket = (int)__u->fd[socket].handle;
#endif
...
...


== Memory Usage ==
A further difference is that the size of the FILE structure differs between Unixlib and SCL, as Unixlib has to hold more information per file to implement full Unix functionality. Again, this normally doesn't matter. The situation where it does is when you mix object files compiled against the two libraries. The solution is not to mix libraries in general.

Instead of using the stack for its heap, Unixlib programs can use a dynamic area for their heap. The traditional way is to set program$heap to any value. e.g:

*set gcc$heap ""

There is another way, however. If you create the variable __dynamic_da_name, your program will automatically use dynamic areas, and use a more sensible name. e.g.:

const char *__dynamic_da_name = "Mozilla Firefox Heap";


== SharedCLibrary API compatibility ==
One instance where it does matter is the use of getc() or getchar(), as these can be (and are, in SharedCLibrary headers) defined as macros which poke with the internals of a file pointer. If you have a library which uses these functions, and which you want to be compatible with both Unixlib and SharedCLibrary, then place:


Unixlib aims to be as compatible with SharedCLibrary as possible. This means it implements all the same C library calls (as required by ANSI C), and also the RISC OS functions such as _swix(), _kernel_swi(), etc.
#undef getc
#undef getchar
#undef feof
#undef ferror
#undef putc
#undef putchar


It's important to note that this means API compatiblity between SharedCLibrary and UnixLib but not necessarily binary compatiblity, i.e. you can't mix object files or libraries built using SharedCLibrary headers with object files or libraries built using UnixLib headers and expect everything will work. In some exceptional cases you can safely fix object files or libraries but it is extremely tricky to get it right and there is no guarantee that this will remain the case in future releases of GCCSDK.
after any #includes in your source file. Desklib, for example, uses this. Of course, you only need to undefine the functions that you use.


== Image Filing Systems ==
== Image Filing Systems ==

Revision as of 18:14, 3 March 2012

Introduction

Unixlib is essentially a Unix interface for RISC OS. It provides three sets of overlapping functionality:

  • It provides Standard C Library functions, to at least ANSI standard (C90 or C99). Thus it is a replacement for the SharedCLibrary.
  • It provides Unix-like functions, a subset of the POSIX specification but with additional non-POSIX functionality.
  • It provides functions to aid porting between Unix and RISC OS.

It is the default C library for GCC for RISC OS.

This document doesn't describe how to use Unixlib in the general case - that is extensively discussed elsewhere. Nor does it discuss the general Unix functionality of Unixlib. As Unixlib attempts to be a full Unix interface, its public functions should be described in the man pages on your favourite real Unix machines. Any deviation from those is probably a bug. Its workings are loosely based on the practices of GNU glibc but sharing only a small percentage of implementation.

What isn't documented elsewhere (or all together in an obvious place) is the extra functionality in Unixlib required for interaction with RISC OS, which is what this document presents.

Filename Translation

UnixLib makes use of principles discussed in RISC OS Filename Translation in order to convert between RISC OS and UNIX formats.

Sometimes it's preferable not to have this translation happen. To disable this, or change the behaviour of the translation, include the file <unixlib/local.h>. Set the variable __riscosify_control to values specified in this header for other actions. e.g.:

 __riscosify_control = __RISCOSIFY_NO_PROCESS;

Often, implicit filename translation isn't enough, and the program will need to do explicit translation. You can achieve this with the __riscosify() and __riscosify_std() functions. You can translate in the other direction with __unixify() and __unixify_std(). In older versions of Unixlib, the function was __uname(), but this is now deprecated and should be avoided. The parameters to these functions are also described in the header file.

Socket numbers

Socket numbers returned by UnixLib do not have the same value as the associated RISC OS socket handles. Most of the time this is not of any importance but sometimes you really need the corresponding RISC OS socket handle for the socket number you got from UnixLib's socket() call (e.g. to interface with the SocketWatch module). In such cases, you can do the following:

For GCCSDK 3.x releases:

 #define __UNIXLIB_INTERNALS
 #include <unixlib/unix.h>
   
 void
 socketwatch_register (int socket)
 {
   socket = (int)__u->fd[socket].handle;
 
 ...

I.e. use the global (and internal) UnixLib resource variable __u.

In the GCCSDK 4.1.1 Pre-release 1 release, the __u is no longer available but an internal UnixLib function __unixlib_getdev could be used instead.

 void
 socketwatch_register (int socket)
 {
   socket = (int)__unixlib_getdev (socket)
 
 ...

In releases after GCCSDK 4.1.1 Pre-release 1, __unixlib_getdev got removed from UnixLib's public API and in the GCCSDK 4.1.2 release, finally a dedicated, stable & public call got foreseen:

 #include <unixlib/local.h>
 
 void
 socketwatch_register(int socket)
 {
   socket = __get_ro_socket (socket);
 
 ...

Memory Usage

Instead of using the stack for its heap, Unixlib programs can use a dynamic area for their heap. The traditional way is to set program$heap to any value. e.g:

  *set gcc$heap ""

There is another way, however. If you create the variable __dynamic_da_name, your program will automatically use dynamic areas, and use a more sensible name. e.g.:

  const char *__dynamic_da_name = "Mozilla Firefox Heap";

SharedCLibrary API compatibility

Unixlib aims to be as compatible with SharedCLibrary as possible. This means it implements all the same C library calls (as required by ANSI C), and also the RISC OS functions such as _swix(), _kernel_swi(), etc.

It's important to note that this means API compatiblity between SharedCLibrary and UnixLib but not necessarily binary compatiblity, i.e. you can't mix object files or libraries built using SharedCLibrary headers with object files or libraries built using UnixLib headers and expect everything will work. In some exceptional cases you can safely fix object files or libraries but it is extremely tricky to get it right and there is no guarantee that this will remain the case in future releases of GCCSDK.

Image Filing Systems

Under RISC OS image files can be treated as either directories or files. Sometimes this can cause programs to get upset, or misbehave if they aren't expecting it. By default, Unixlib treats image files as diretories. To change this at runtime:

 #include <unixlib/features.h>
 
 ...
 
 __feature_imagefs_is_file = 1;
GCC and GCCSDK pages
GCC under RISC OS

GCC for RISC OS, GCC tutorial, GCC common switches, GCC for beginners, UnixLib, ELFLoader
GCCSDK and Unix porting
GCCSDK, GCCSDK Releases, GCCSDK Development, Using GCCSDK, Autobuilder Development and Packaging Cygwin setup, Accelerating autobuilder with apt-proxy, ChoX11, Developer help wanted