shithub: docs.9front.org

ref: f14db990f495096c3095a493c54b0750bb1382b4
dir: docs.9front.org/porting.md

View raw version
# Porting alien software *without* APE

Before getting started, make sure you wrote a decent amount of C and
(mostly) aware of what you're doing.

Ask around, perhaps someone already made the port.

Consider writing a native program (or library) from scratch before
approaching a port.

Do NOT port anything for the sake of "porting" alone.

## Process

*It might be the easiest to install and use*
[npe](https://git.sr.ht/~ft/npe).

But, for a _complete_ DIY, in case you *REALLY* want it, there is
[helpmeport](https://git.sr.ht/~ft/snippets/blob/master/helpmeport)
script.  It tries to generate the appopriate headers and a `mkfile`:

	cd coollib
	# sometimes, the source files are located in `src` subdir
	# if it's in the current directory, just specify `.` instead
	rm -rf mkfile src/plan9 # remove old stuff
	helpmeport src | rc
	# now there is `src/plan9` directory and `mkfile`
	# `mkfile` needs manual adjustments: open it and search for "FIXME"
	# make your choices (name of the library/program, etc)
	# clean up headers and sources, some of them might be platform-specific
	B mkfile
	# now try to build. there is 99% it won't work the first time
	mk

Depending on the result of the build, some changes of the source code
might be required.

The script will provide `__plan9__` and eg `__amd64__` definitions to
be used throughout, in case needed.

Note that `helpmeport` is unsupported.

## Common issues

Before trying to run anything, check the pragmas.

	g pragma

`#pragma pack(push)` and `#pragma pack(pop)` have to be replaced with
`#pragma pack on` and `#pragma pack off`.

`#pragma once` isn't supported either and, unless the project builds
fine, the header's contents with the pragma have to be enclosed in:

	#ifndef _header_name_h_
	#define _header_name_h_
	....
	#endif

For a more or less automated processing you could use a script:

```
fn pragma_once {
	h=_^`"{echo $1 | sed 's,.*/,,g;s/\..*//g' | tr -d '
'}^_h_
	sed 's/#pragma once/#ifndef '^$h^'\n#define '^$h^'/g' $1 && echo && echo '#endif'
}

for(f in src/*.h src/*/*.h){
	grep -s '^#pragma[ 	]+once' $f && {
		pragma_once $f >$f.p
		mv $f.p $f
	}
}
```

### function not declared: ...

If the function defined in the project, and has no arguments, make
sure it's declared as `(void)` instead of `()`.

### alloca

`alloca` allocates memory on stack, so that freeing isn't required.
Plan 9 does not have that.  It has to be replaced with `malloc`.
`free` call HAS to be added, before leaving the function, or else you
WILL have memory leaks.

### *_MAX or *_MIN not declared

Grep `/sys/include` to see if it's already defined in APE:

	g UCHAR_MAX /sys/include/ape

In most of the cases, you can just add it to `src/plan9/plan9.h`.  Be
careful if the size depends on the CPU you're targetting.

### Some POSIX standard function is missing

You could copy it from APE (`/sys/src/ape`) or just roll out your own.

### Floating point exceptions

By default, Plan 9 has various exceptions enabled.  Try
`setfcr(getfcr() & ~(FPINVAL|FPOVFL))` in `main` function before
running any of the ported logic.

### Some weird stuff with types/signatures not matching during linking

This is probably caused by the compiler getting confused with forward
declarations of certain types.  One object file seems to have one
type, the other object file has a slightly different type with the
same name.  Your best bet is to check the functions that error report
is about.  One thing that has been found to help with cases like this
(in case you're *sure* the types are correct):

	#ifdef __plan9__
	#pragma incomplete struct my_cool_struct
	#endif

placed after the type declaration.  It will tell the compiler not to
bother too much.

## Uncommon issues

Your program builds fine, runs fine, doesn't crash, but produces
incorrect result.  Chances are, you missed a `#pragma pack ...`, or
perhaps there is a comparison between shorter (one or two-byte) types
of different signedness.  That produces different result in Plan 9 C
compiler.

## Issues nobody wants to help you with

* `wchar_t`. No.
* `int128_t`. Just give up.
* `pthread_*`.  Best is to give up.  If you *really* know what you're doing, take a look at [these ones](https://git.sr.ht/~ft/dav1d/blob/master/src/plan9_thread.c).