source: project/wiki/porting-c4-to-c5 @ 37543

Last change on this file since 37543 was 36286, checked in by svnwiki, 2 years ago

Anonymous wiki edit for IP [185.220.102.8]:

File size: 18.0 KB
Line 
1[[toc:]]
2
3== Porting CHICKEN 4 code to CHICKEN 5
4
5This guide will take you by the hand and explain how to port code from
6CHICKEN 4 to CHICKEN 5.  If your code is an egg, you might want to
7manually compile the source components at first before finishing up
8the egg itself.
9
10Please read it through and if you hit any issues not in this document
11which you think are important to note, add them to this page.  It's a
12wiki after all!  With your additions you'll be saving others from the
13same pain.
14
15If you prefer to first fix the egg's compilation infrastructure,
16scroll down to the [[#Re-packaging eggs|section on egg (re-)packaging]],
17then go back up and take care of your code afterwards.
18
19=== Begin with the easy part: replacing module imports
20
21When you have some CHICKEN 4 code to port to CHICKEN 5, the best way
22to get started is by first installing all the eggs you know are
23needed.
24
25Then, in your code, replace every {{use}} and {{require-extension}}
26with {{import}}, and then compile the code.
27
28This should give lots of errors about unknown modules.  If you are
29using any of the following modules from CHICKEN 4 core, these have
30moved to an egg so you should install the corresponding egg before
31proceeding:
32
33* [[/eggref/5/srfi-1|srfi-1]]
34* [[/eggref/5/srfi-13|srfi-13]]
35* [[/eggref/5/srfi-14|srfi-14]]
36* [[/eggref/5/srfi-18|srfi-18]]
37* [[/eggref/5/srfi-69|srfi-69]]
38
39Some other procedures have also been moved into eggs, but we'll deal
40with those later.  Installing these "large" eggs will take care of
41fixing the bulk of your import issues.
42
43Now, after you've installed the required eggs you can recompile, and
44you'll typically still get errors about nonexisting core modules (like
45"chicken", "extras", "posix" and so on).  The easiest way to get rid
46of this is to simply '''remove''' those modules from your import
47forms, and then retrying the compilation.
48
49If your code is wrapped in a module, eventually, you'll be left only
50with errors about missing imports, and cascade-style errors caused by
51missing macros (these can be very misleading, so pay attention!).  For
52example, when I was porting the [[/eggref/5/uri-generic|uri-generic
53egg]], I got this list after I had replaced {{use}} by {{import}} and
54installed the requisite SRFI eggs:
55
56    Warning: reference to possibly unbound identifier `->string' in:
57    Warning:    uri-normalize-case
58    Warning:    suggesting: `(import chicken.string)'
59   
60    Warning: reference to possibly unbound identifier `conc'
61    Warning:    suggesting: `(import chicken.string)'
62   
63    Warning: reference to possibly unbound identifier `reverse-list->string' in:
64    Warning:    uri-char-list->string
65    Warning:    suggesting: `(import chicken.string)'
66   
67    Warning: reference to possibly unbound identifier `string-intersperse' in:
68    Warning:    join-segments
69    Warning:    suggesting: `(import chicken.string)'
70   
71    Warning: reference to possibly unbound identifier `with-output-to-string' in:
72    Warning:    uri->string
73    Warning:    suggesting: `(import chicken.port)'
74   
75    Warning: reference to possibly unbound identifier `fprintf'
76    Warning:    suggesting: `(import chicken.format)'
77   
78    Warning: reference to possibly unbound identifier `out'
79   
80    Warning: reference to possibly unbound identifier `x'
81   
82    Warning: reference to possibly unbound identifier `define-record-printer'
83    Warning:    suggesting: `(import chicken.base)'
84   
85    Warning: reference to possibly unbound identifier `URIAuth-port-set!'
86   
87    Warning: reference to possibly unbound identifier `URIAuth-port' in:
88    Warning:    uri-auth->list
89    Warning:    uri-auth-equal?
90    Warning:    uri-port
91    Warning:    update-URIAuth
92   
93    Warning: reference to possibly unbound identifier `URIAuth-host-set!'
94   
95    Warning: reference to possibly unbound identifier `URIAuth-host' in:
96    Warning:    uri-auth->list
97    Warning:    uri-auth-equal?
98    Warning:    uri-host
99    Warning:    update-URIAuth
100   
101    Warning: reference to possibly unbound identifier `URIAuth-password-set!'
102   
103    Warning: reference to possibly unbound identifier `URIAuth-password' in:
104    Warning:    uri-auth->list
105    Warning:    uri-auth-equal?
106    Warning:    uri-password
107    Warning:    update-URIAuth
108   
109    Warning: reference to possibly unbound identifier `URIAuth-username-set!'
110   
111    Warning: reference to possibly unbound identifier `URIAuth-username' in:
112    Warning:    uri-auth->list
113    Warning:    uri-auth-equal?
114    Warning:    uri-username
115    Warning:    update-URIAuth
116   
117    Warning: reference to possibly unbound identifier `URIAuth?' in:
118    Warning:    ucdiff?
119    Warning:    uri-auth->list
120   
121    Warning: reference to possibly unbound identifier `password'
122   
123    Warning: reference to possibly unbound identifier `username'
124   
125    Warning: reference to possibly unbound identifier `make-URIAuth' in:
126    Warning:    authority
127    Warning:    loop
128   
129    Warning: reference to possibly unbound identifier `<URIAuth>'
130   
131    Warning: reference to possibly unbound identifier `URI-fragment-set!'
132   
133    Warning: reference to possibly unbound identifier `URI-fragment' in:
134    Warning:    uri->list
135    Warning:    uri-equal?
136    Warning:    update-uri*
137    Warning:    update-URI
138   
139    Warning: reference to possibly unbound identifier `URI-query-set!'
140   
141    Warning: reference to possibly unbound identifier `URI-query' in:
142    Warning:    uri-relative-to
143    Warning:    uri->list
144    Warning:    uri-equal?
145    Warning:    update-uri*
146    Warning:    update-URI
147   
148    Warning: reference to possibly unbound identifier `URI-path-set!'
149   
150    Warning: reference to possibly unbound identifier `URI-path' in:
151    Warning:    uri-relative-to
152    Warning:    uri->list
153    Warning:    uri-equal?
154    Warning:    update-uri*
155    Warning:    update-URI
156   
157    Warning: reference to possibly unbound identifier `URI-authority-set!'
158   
159    Warning: reference to possibly unbound identifier `URI-authority' in:
160    Warning:    uri-relative-to
161    Warning:    uri->list
162    Warning:    uri-equal?
163    Warning:    loop
164    Warning:    uri-password
165    Warning:    uri-username
166    Warning:    uri-port
167    Warning:    uri-host
168    Warning:    update-URI
169   
170    Warning: reference to possibly unbound identifier `URI-scheme-set!'
171   
172    Warning: reference to possibly unbound identifier `URI-scheme' in:
173    Warning:    uri-relative-to
174    Warning:    uri->list
175    Warning:    uri-equal?
176    Warning:    update-uri*
177    Warning:    update-URI
178   
179    Warning: reference to possibly unbound identifier `URI?' in:
180    Warning:    uri->list
181    Warning:    uri->string
182   
183    Warning: reference to possibly unbound identifier `path'
184   
185    Warning: reference to possibly unbound identifier `make-URI' in:
186    Warning:    failure29947
187    Warning:    relative-ref
188    Warning:    uri
189    Warning:    make-uri
190    Warning:    make-uri*
191    Warning:    loop
192   
193    Warning: reference to possibly unbound identifier `<URI>'
194   
195    Warning: reference to possibly unbound identifier `define-record-type'
196    Warning:    suggesting one of:
197    Warning:    (import chicken.base)
198    Warning:    (import srfi-9)
199   
200    Warning: reference to possibly unbound identifier `error'
201    Warning:    suggesting one of:
202    Warning:    (import chicken.base)
203    Warning:    (import srfi-23)
204   
205    Error: module unresolved: uri-generic
206
207This long list looks pretty intimidating, but it's not that hard to
208fix, actually.  The way to do that is to quickly skim the suggestions.
209Oftentimes you'll get lots of errors about procedures that don't
210directly come from missing imports, like in this case (all the
211URI-blabla procedures being undefined).
212
213If you look closely, you'll notice that all of these follow a certain
214naming pattern: {{URI-foo}} or {{URI-foo-set!}}.  This points us to
215the fact that they are record accessors.  You'll also notice the
216suggestion mentioning {{define-record-type}}, which is exactly what we
217need to import to fix all these errors.
218
219Especially when you're using defining macros like you'll see lots of
220these kinds of errors repeated all over the place where the
221definitions are used.  So, be aware that this can make the output a
222bit confusing.  If you have large macros with lots of keywords.
223That's why it's usually best to start getting your macro imports in
224order, then recompiling to get rid of all the excess noise.
225
226In my example of uri-generic, after ''just'' adding {{(import (chicken
227base))}}, which I prefer over {{(import chicken.base)}}, the number of
228warnings/errors were drastically reduced:
229
230    Warning: reference to possibly unbound identifier `->string' in:
231    Warning:    uri-normalize-case
232    Warning:    suggesting: `(import chicken.string)'
233   
234    Warning: reference to possibly unbound identifier `conc'
235    Warning:    suggesting: `(import chicken.string)'
236   
237    Warning: reference to possibly unbound identifier `reverse-list->string' in:
238    Warning:    uri-char-list->string
239    Warning:    suggesting: `(import chicken.string)'
240   
241    Warning: reference to possibly unbound identifier `string-intersperse' in:
242    Warning:    join-segments
243    Warning:    suggesting: `(import chicken.string)'
244   
245    Warning: reference to possibly unbound identifier `with-output-to-string' in:
246    Warning:    uri->string
247    Warning:    suggesting: `(import chicken.port)'
248   
249    Warning: reference to possibly unbound identifier `fprintf'
250    Warning:    suggesting: `(import chicken.format)'
251   
252    Error: module unresolved: uri-generic
253
254After adding the suggested imports, the code compiled cleanly and the
255tests ran without problems, after I fixed a few trivial imports in the
256test suite.
257
258So you see, even for medium sized eggs like uri-generic, porting
259'''can''' be a breeze.  But beware, there are situations where things
260can get hairier!
261
262
263=== Fixing more missing procedures by installing eggs
264
265After you've fixed your core imports and installed the SRFI eggs, you
266might notice some problems if you're using particular procedures from
267old core modules that are no longer available.  Some of those have
268been moved into separate eggs.  If this is the case with your code,
269take a look through the list below.
270
271Some procedures from the "utils" module have been moved into several
272eggs:
273
274* [[/eggref/5/compile-file|compile-file]]
275* [[/eggref/5/scan-input-lines|scan-input-lines]]
276
277Some procedures from "lolevel" have been moved into an
278[[/eggref/5/object-evict|object-evict]] egg:
279
280* {{object-evict}}
281* {{object-evict-to-location}}
282* {{object-evicted?}}
283* {{object-release}}
284* {{object-unevict}}
285* {{object-size}}
286
287The following procedures from {{data-structures}} have been moved to
288the [[/eggref/5/queues|queues]] egg:
289
290* {{list->queue}}
291* {{make-queue}}
292* {{queue?}}
293* {{queue-length}}
294* {{queue->list}}
295* {{queue-add!}}
296* {{queue-empty?}}
297* {{queue-first}}
298* {{queue-last}}
299* {{queue-remove!}}
300* {{queue-push-back!}}
301* {{queue-push-back-list!}}
302
303And the [[/eggref/5/binary-search|binary-search]] procedure from
304{{data-structures}} has also been put into its own egg.
305
306From the {{posix}} module, memory mapped I/O has been moved into
307its own [[/eggref/5/memory-mapped-files|memory-mapped-files]] egg.
308Specifically, these procedures have been moved there:
309
310* {{memory-mapped-file?}}
311* {{map-file-to-memory}}
312* {{memory-mapped-file-pointer}}
313* {{unmap-file-from-memory}}
314
315Also removed from {{posix}} are the group information procedures,
316which have been moved to the [[/eggref/5/posix-groups|posix-groups]]
317egg.  These are the following:
318
319* {{group-information}}
320* {{initialize-groups}}
321* {{get-groups}}
322* {{set-groups!}}
323
324Lastly, a few macros from {{chicken}} were moved into the
325[[/eggref/5/miscmacros|miscmacros]] egg:
326
327* {{eval-when}}
328* {{ensure}}
329* {{select}}
330
331
332=== Random and random-bsd
333
334The {{random}} procedure produced very weak random numbers, so we've
335deleted it.  Instead, you can import [[/man/5/Module (chicken
336random)|{{(chicken random)}}]] and use {{pseudo-random-integer}},
337which should produce random numbers in the range between 0 and the
338number you supply (exclusive).  Its argument '''must''' be an exact
339integer.
340
341If you were using the random-bsd egg (which produced slightly better
342random numbers), it's probably best to use the built-in random number
343generator.
344
345If before you would divide by a floating-point number to get a number
346in the range 0..1, you can now use {{(pseudo-random-real)}}, which
347will do the same thing, but in a better way.
348
349If you need to initialize the PRNG to a known state, instead of
350{{randomize}}, you can use {{set-pseudo-random-seed!}}, but be aware
351that the numbers you'll get will be different.
352
353For cryptographic uses or other uses that require "really" random
354numbers, you can use {{random-bytes}}, which returns numbers from the
355operating system's entropy source.
356
357=== Fixing more subtle issues
358
359Then, there are some semantic changes.  These are of course listed in
360the {{NEWS}} file, but let's take a look at some of the more important
361ones:
362
363
364==== read-string returns {{#!eof}} instead of {{""}} at end of file
365
366The title says it all: The
367[[/man/5/Module (chicken io)#read-string|read-string]] procedure
368now returns {{#!eof}} when the end of file is hit, instead of an
369empty string.  This is more consistent and allows one to distinguish
370between a successful read of zero characters and an exhausted file
371descriptor.
372
373This is listed first because it's quite tricky and can cause very
374subtle bugs, so be very careful about this one in particular.
375I hope you have a good test suite! :)
376
377==== '...'expected syntax-transformer, but got: #<procedure (? f r c)>
378
379You are probably using a define-syntax call with a procedure as argument.
380This has been deprecated. You need to wrap this inside a er-macro-transformer or ir-macro-transformer expression.
381
382==== process, process* and process-execute argument type change
383
384The third argument for these three procedures is now an association list instead of a list of strings.
385
386For example, this CHICKEN 4 code:
387<enscript highlight="scheme">
388(process-execute "/usr/bin/env" '() '("VARIABLE=VALUE"))
389</enscript>
390
391Becomes this for CHICKEN 5:
392<enscript highlight="scheme">
393(process-execute "/usr/bin/env" '() '(("VARIABLE" . "VALUE")))
394</enscript>
395
396==== repository-path type change
397
398The (repository-path) parameter, living in the (chicken platform) module, now contains a list of strings instead of a string, representing the multiple repository directories requested by the user.
399
400Change in the code would look like this, for example:
401<enscript highlight="scheme">
402;; Changing this:
403(repository-path "awesome-repository")
404;; to this
405(repository-path '("awesome-repository")) ;; if you want to replace the user choice
406;; or
407(repository-path (cons "awesome-repository" (repository-path))) ;; if you want to extend it
408</enscript>
409
410==== FFI integers arguments require fixnum or bignum values
411
412Now that support for the full numeric tower, support for floating point
413values behaving like integers has been removed. The FFI layer does not
414convert flonum to integers when passing them as arguments to C functions
415any longer.
416
417<enscript highlight="scheme">
418;; As an example:
419
420 ;; might come from an external library, like JSON parsing (where every number is floating point)
421(define milliseconds-time 1534096420492.0)
422
423;; CHICKEN 4 way
424; (seconds->local-time (/ milliseconds-time 1000))
425
426;; CHICKEN 5 way
427(seconds->local-time (inexact->exact (round (/ milliseconds-time 1000))))
428</enscript>
429
430==== Linking to external libraries
431
432In CHICKEN 5, the {{-l}} flag was removed, you now have to use {{-L -llib}}.
433
434For example:
435<enscript highlight="sh">
436# Something compiled like so:
437csc program.scm -lncurses
438# Would now be compiled like this:
439csc program.scm -L -lncurses
440</enscript>
441
442==== Manually created record instances
443
444In CHICKEN 5 structure tags created by records (as defined with {{define-record}}, etc.
445are by default qualified with the module name. Sometimes code creates these record instances
446manually (i.e. by using {{##sys#make-structure}}, which must take this qualification into
447account, e.g.:
448
449<enscript highlight="scheme">
450(module foo ()
451  (import scheme (chicken base))
452  (define-record baz)
453  (print (eq? (make-baz) (##sys#make-structure 'baz))))   ; ==> prints "#f"
454</enscript>
455
456=== Re-packaging eggs
457
458If your code is an egg, you'll have to rewrite your setup file into
459the new "declarative" format.  There's a [[/man/5/Extensions#creating-eggs|short description]] on how to create eggs for CHICKEN 5 in the manual,
460as well as a [[/man/5/Egg specification format|complete reference]] on
461the new file format.
462
463Basically, the new way to make an egg involves writing a {{.egg}}
464file.  This looks a lot like the old {{.meta}} file, with the author,
465name, license and dependency declarations.  Added to this are
466"components", which make up the egg's sources.
467
468For simple eggs, this is also trivial.  Here's uri-generic's old
469{{.meta}} file:
470
471<enscript highlight="scheme">
472((egg "uri-generic.egg")
473 (license "BSD")
474 (category web)
475 (needs matchable)
476 (test-depends test)
477 (author "Ivan Raikov, Peter Bex, Seth Alves")
478 (synopsis "URI generic syntax (RFC 3986) parsing and manipulation."))
479</enscript>
480
481And its {{.setup}} file:
482
483<enscript highlight="scheme">
484(standard-extension 'uri-generic "2.43")
485</enscript>
486
487After porting this to CHICKEN 5's {{.egg}} file, you get:
488
489<enscript highlight="scheme">
490((license "BSD")
491 (category web)
492 (dependencies matchable srfi-1 srfi-13 srfi-14)
493 (test-dependencies test)
494 (author "Ivan Raikov, Peter Bex, Seth Alves")
495 (synopsis "URI generic syntax (RFC 3986) parsing and manipulation.")
496 (components (extension uri-generic)))
497</enscript>
498
499As you can see, for eggs consisting of a single file, this is very
500straightforward: just add any missing egg dependencies for the stuff
501that has moved out of core, remove obsolete forms like {{(egg ..)}},
502replace {{needs}} or {{depends}} with {{dependencies}}, replace
503{{test-depends}} to {{test-dependencies}} and add a {{(components
504(extension ..))}} entry which corresponds to {{standard-extension}}
505from the old {{.setup}} file.
506
507For more complex examples of {{.egg}} files, just look through the
508[[https://wiki.call-cc.org/chicken-projects/egg-index-5.html|list of available CHICKEN 5 eggs]].
509There are a few in there with multiple source files and even some with
510custom build scripts.
Note: See TracBrowser for help on using the repository browser.