better dependency management
[m6w6/ext-psi] / README.md
1 # ext-psi
2
3 [![Build Status](https://travis-ci.org/m6w6/ext-psi.svg?branch=master)](https://travis-ci.org/m6w6/ext-psi)
4
5 PSI is a PHP extension, which provides a foreign function interface through
6 `libffi` and/or `libjit`.
7
8 The acronym PSI may be read as:
9 * PHP System Interface
10 * POSIX Standard Interface
11
12 The latter because PSI can be configured to include declarations for most of the
13 [base definitions and system interfaces of POSIX.1-2008](http://pubs.opengroup.org/onlinepubs/9699919799/).
14
15 > **WARNING:**
16 > This is heavy WIP. Only a small part of configuration and implementation has been completed yet.
17
18 ## Features
19
20 * standard scalar types mapped to stdint types
21 * structs, unions, enums and typedefs
22 * simple numeric expressions
23 * string and int constants
24 * vararg calls
25
26 ## Installing
27
28 > **WARNING:**
29 > This is heavy WIP. Installation only works from a source checkout yet.
30
31 ### PECL
32
33 This extension is distributed through [PECL](http://pecl.php.net) and can be
34 installed with [PEAR](http://pear.php.net)'s pecl command:
35
36 pecl install psi
37
38 ### PHARext
39
40 Watch out for [PECL replicates](https://replicator.pharext.org?psi)
41 and [pharext](https://github.com/pharext) packages attached to
42 [releases](https://github.com/m6w6/ext-psi/releases).
43
44 ### Checkout
45
46 This extension is hosted at [Github](https://github.com/m6w6/ext-psi) with a
47 personal [mirror](https://git.m6w6.name/?p=m6w6/ext-psi) available.
48
49 git clone github.com:m6w6/ext-psi
50
51 cd ext-psi
52
53 /path/to/phpize
54 ./configure --with-php-config=/path/to/php-config
55 make
56 sudo make install
57
58 ## Configuring PSI at build time
59
60 PSI supports the following configure switches:
61
62 ### --enable-psi
63 **Enable PHP System Interface support.**
64
65 This is only relevant for an in-tree build. Use `--enable-psi` to include
66 the PSI extension in the build.
67
68 ### --enable-psi-posix
69 **Pre-define POSIX decls.**
70
71 Use `--enable-psi-posix=all` to enable all available POSIX checks.
72
73 Use `--enable-psi-posix=section,another,onemore` to enable specific modules only.
74
75 The following modules are included by default:
76
77 [stdint](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdint.h.html),
78 [stddef](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html),
79 [stdlib](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdlib.h.html),
80 [sys/types](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html)
81
82 The following modules are available to select:
83
84 [errno](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html),
85 [fcntl](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html),
86 [glob](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/glob.h.html),
87 [locale](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html),
88 [ndbm](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/ndbm.h.html),
89 [netdb](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html),
90 [netinet/in](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html),
91 [netinet/tcp](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_tcp.h.html),
92 [poll](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html),
93 [signal](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html),
94 [stdio](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdio.h.html),
95 [sys/select](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_select.h.html),
96 [sys/socket](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html),
97 [sys/stat](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html),
98 [sys/time](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html),
99 [sys/times](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_times.h.html),
100 [sys/uio](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_uio.h.html),
101 [sys/utsname](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_utsname.h.html),
102 [syslog](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/syslog.h.html),
103 [time](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html),
104 [unistd](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html),
105 [wchar](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/wchar.h.html),
106 [wctype](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/wctype.h.html),
107
108 ### --with-psi-libjit
109 **Path to libjit.**
110
111 > **WARNING:**
112 > We currently rely on a patched libjit, because of an apparent bug in how
113 > libjit creates closures, which still needs to be verified, though.
114 > See https://github.com/m6w6/libjit for the preliminary patch.
115
116 ### --with-psi-libffi
117 **Path to libffi.**
118
119 ## Configuring PSI at runtime
120
121 ### psi.engine
122
123 The backend that PSI should use as FFI, either _jit_ for `libjit` or _ffi_ for `libffi`. Defaults to "ffi".
124
125 ### psi.directory
126
127 A colon separated list of directories to scan for `*.psi` files. Defaults to "psi.d".
128
129 ## PSI files
130
131 ### Comments
132
133 * C style multi line comments
134 * C++ style single line comments
135 * CPP directives are ignored, so the hash sign basically works as single line comment
136
137 ```c
138 // this is a one line comment
139 /* followed
140 by a multi
141 line comment
142 */
143 # this looks like a pre-processor directive and is ignored
144 ```
145
146 ### Typedefs
147
148 ```c
149 typedef unsigned char xmlChar;
150 ```
151
152 They follow the basic C-style `typedef` syntax.
153
154 ```c
155 typedef struct str {
156 char *p;
157 size_t l;
158 } str_t;
159 ```
160 You can also `typedef` unions and enums that way.
161
162 ### Structs
163
164 The following example results in exactly the same interpretation as the previous:
165
166 ```c
167 typedef struct str str_t;
168 struct str {
169 char *p;
170 size_t l;
171 }
172 ```
173
174 A struct will have the size of all its elements plus padding combined and an
175 alignment equal to that of the largest element's alignment.
176
177 ### Enums
178
179 Enums are considered to be of type `int`.
180
181 ```c
182 enum STATUS {
183 FAILURE = -1,
184 SUCCESS
185 }
186 ```
187
188 Enums will be registered as userland constants with the following pattern:
189
190 * `psi\STATUS\FAILURE` with value -1
191 * `psi\STATUS\SUCCESS` with value 0
192
193 ### Unions
194
195 ```c
196 union anyval {
197 char c;
198 short s;
199 int i;
200 long l;
201 float f;
202 double d;
203 str_t str;
204 }
205 ```
206
207 Unions will have the size and alignment of the largest element they contain.
208
209 ### Lib
210
211 ```c
212 lib "awesome";
213 ```
214
215 These statements define what library should be `dlopen()`-ed to look up symbols from declarations.
216 They must only occur once in a file. When a `lib` statement is omitted, stdlib is assumed.
217
218 ### Declarations
219
220 Declarations provide all information needed to make a foreign function call.
221
222 ```c
223 extern char *strerror(int errnum);
224 ```
225
226 You may specify a non-standard calling convention in place of `extern`, where `default` and `cdecl` have the same meaning as `extern`.
227
228 Additionally recognized calling conventions include: `mscdecl`, `stdcall` and `fastcall`.
229
230 ### Constants
231
232 ```c
233 const int num\ZERO = 0;
234 const string pwd\TOKEN = "4WlOjXGL";
235 ```
236
237 Constants must have a namespaced identifiers and are registered as userland constants.
238
239 ### Implementations
240
241 Implementations are the userland visible interfaces to the foreign function interface.
242
243 ```php
244 function str\error(int $num) : string {
245 let errnum = intval($num);
246 return to_string(strerror);
247 }
248 ```
249
250 Each implementation refers to exactly one declared foreign function referenced in its `return` statement. Each declaration, on the other hand, may have any number of implementations.
251
252 ## Complete example
253
254 ```c
255 # all declarations in this file should be looked up in libidn
256 lib "idn";
257
258 # IDNA errors
259 const int \IDNA_SUCCESS = 0;
260 const int \IDNA_STRINGPREP_ERROR = 1;
261 const int \IDNA_PUNYCODE_ERROR = 2;
262 const int \IDNA_CONTAINS_NON_LDH = 3;
263 const int \IDNA_CONTAINS_LDH = 3;
264 const int \IDNA_CONTAINS_MINUS = 4;
265 const int \IDNA_INVALID_LENGTH = 5;
266 const int \IDNA_NO_ACE_PREFIX = 6;
267 const int \IDNA_ROUNDTRIP_VERIFY_ERROR = 7;
268 const int \IDNA_CONTAINS_ACE_PREFIX = 8;
269 const int \IDNA_ICONV_ERROR = 9;
270 const int \IDNA_MALLOC_ERROR = 201;
271 const int \IDNA_DLOPEN_ERROR = 202;
272 # IDNA flags
273 const int \IDNA_ALLOW_UNASSIGNED = 1;
274 const int \IDNA_USE_STD3_ASCII_RULES = 2;
275
276 # nothing special about the declaration here
277 default int idna_to_ascii_8z(char *host, char **buffer, int flags);
278
279 function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int {
280 # there must be a `let` statement for each
281 # declared argument of the called function
282
283 # setup a pointer to NULL
284 let buffer = &NULL;
285
286 # setup a string pointer to $host
287 let host = strval($host);
288
289 # assing the integer value of $flags
290 let flags = intval($flags);
291
292 # the function to call is referenced in
293 # the return statement, along with the
294 # neccessary cast how to interpred the
295 # returned native value
296 return to_int(idna_to_ascii_8z);
297
298 # by-ref vars might receive output values
299 # through `set` statments, which also
300 # require a cast how to marshal the
301 # native data as PHP value
302 set $result = to_string(*buffer);
303
304 # after the buffer has been marshaled
305 # for the PHP engine, we have to free
306 # the buffer to avoid a memory leak
307 free free(*buffer);
308 # note that in this example we omit the
309 # declaration of the free() function called
310 # in our `free` statement for brevity
311 }
312
313 default char *idna_strerror(int rc);
314 function idn\strerror(int $rc) : string {
315 return to_string(idna_strerror);
316 let rc = intval($rc);
317 }
318 ```
319
320 ### Userland
321
322 ```php
323 $rc = idn\utf8_to_ascii("flöte.de", $result);
324 printf("<%s>\n", $result);
325 printf("%s\n", idn\strerror($rc));
326
327 $rc = idn\utf8_to_ascii("…asdf….de", $result, IDNA_USE_STD3_ASCII_RULES);
328 printf("<%s>\n", $result);
329 printf("%s\n", idn\strerror($rc));
330 ```
331
332 #### Output
333 ```
334 <xn--flte-6qa.de>
335 Success
336 <>
337 Non-digit/letter/hyphen in input
338 ```
339
340 ## ChangeLog
341
342 A comprehensive list of changes can be obtained from the
343 [PECL website](https://pecl.php.net/package-changelog.php?package=psi).
344
345 Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO).
346
347 ## License
348
349 ext-psi is licensed under the 2-Clause-BSD license, which can be found in
350 the accompanying [LICENSE](./LICENSE) file.
351
352 ## Contributing
353
354 All forms of contribution are welcome! Please see the bundled
355 [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed.
356
357 The list of past and current contributors is maintained in [THANKS](./THANKS).