~ chicken-core (master) /csc.scm
Trap1;;;; csc.scm - Driver program for the CHICKEN compiler - felix -*- Scheme -*-
2;
3; Copyright (c) 2008-2022, The CHICKEN Team
4; Copyright (c) 2000-2007, Felix L. Winkelmann
5; All rights reserved.
6;
7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
8; conditions are met:
9;
10; Redistributions of source code must retain the above copyright notice, this list of conditions and the following
11; disclaimer.
12; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
13; disclaimer in the documentation and/or other materials provided with the distribution.
14; Neither the name of the author nor the names of its contributors may be used to endorse or promote
15; products derived from this software without specific prior written permission.
16;
17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25; POSSIBILITY OF SUCH DAMAGE.
26
27
28(module main ()
29
30(import scheme
31 chicken.base
32 chicken.file
33 chicken.fixnum
34 chicken.foreign
35 chicken.format
36 chicken.io
37 chicken.pathname
38 chicken.platform
39 chicken.process
40 chicken.process-context
41 chicken.irregex
42 chicken.string)
43
44(include "egg-environment.scm")
45(include "mini-srfi-1.scm")
46
47(define-foreign-variable windows-shell bool "C_WINDOWS_SHELL")
48(define-foreign-variable POSTINSTALL_PROGRAM c-string "C_INSTALL_POSTINSTALL_PROGRAM")
49(define-foreign-variable INSTALL_LIB_NAME c-string "C_INSTALL_LIB_NAME")
50(define-foreign-variable TARGET_LIB_NAME c-string "C_TARGET_LIB_NAME")
51(define host-libs (string-split (foreign-value "C_INSTALL_MORE_LIBS" c-string)))
52(define-foreign-variable TARGET_MORE_STATIC_LIBS c-string "C_TARGET_MORE_STATIC_LIBS")
53(define-foreign-variable INSTALL_MORE_STATIC_LIBS c-string "C_INSTALL_MORE_STATIC_LIBS")
54(define TARGET_CC default-cc)
55(define-foreign-variable CHICKEN_PROGRAM c-string "C_CHICKEN_PROGRAM")
56(define-foreign-variable TARGET_FEATURES c-string "C_TARGET_FEATURES")
57(define-foreign-variable TARGET_RUN_LIB_HOME c-string "C_TARGET_RUN_LIB_HOME")
58(define-foreign-variable TARGET_RC_COMPILER c-string "C_TARGET_RC_COMPILER")
59(define-foreign-variable INSTALL_RC_COMPILER c-string "C_INSTALL_RC_COMPILER")
60(define-foreign-variable TARGET_LDFLAGS c-string "C_TARGET_LDFLAGS")
61(define-foreign-variable INSTALL_LDFLAGS c-string "C_INSTALL_LDFLAGS")
62(define-foreign-variable CSC_PROGRAM c-string "C_CSC_PROGRAM")
63
64
65;;; Parameters:
66
67(define windows (eq? (software-type) 'windows))
68(define mingw (eq? (software-version) 'mingw))
69(define osx (eq? (software-version) 'macosx))
70(define cygwin (eq? (software-version) 'cygwin))
71(define aix (eq? (build-platform) 'aix))
72(define solaris (memq (software-version) '(solaris sunos)))
73
74(define elf
75 (memq (software-version) '(linux netbsd freebsd solaris openbsd hurd haiku)))
76
77(define (stop msg . args)
78 (fprintf (current-error-port) "~a: ~?~%" CSC_PROGRAM msg args)
79 (exit 64) )
80
81(define arguments (command-line-arguments))
82(define cross-chicken (feature? #:cross-chicken))
83(define host-mode (or (not cross-chicken) (member "-host" arguments)))
84
85(define (back-slash->forward-slash path)
86 (if windows-shell
87 (string-translate path #\\ #\/)
88 path))
89
90(define (quotewrap str)
91 (qs (back-slash->forward-slash (normalize-pathname str))))
92
93(define home
94 (if host-mode host-sharedir default-sharedir))
95
96(define translator
97 (make-pathname host-bindir CHICKEN_PROGRAM))
98
99(define compiler (if host-mode host-cc default-cc))
100(define c++-compiler (if host-mode host-cxx default-cxx))
101(define rc-compiler (if host-mode INSTALL_RC_COMPILER TARGET_RC_COMPILER))
102(define linker (if host-mode host-cc default-cc))
103(define c++-linker (if host-mode host-cxx default-cxx))
104(define object-extension (if mingw "obj" "o"))
105(define library-extension "a")
106(define link-output-flag "-o")
107(define executable-extension "")
108(define compile-output-flag "-o")
109(define shared-library-extension ##sys#load-dynamic-extension)
110(define static-object-extension (##sys#string-append "static." object-extension))
111(define static-library-extension (##sys#string-append "static." library-extension))
112(define default-translation-optimization-options '())
113(define pic-options (if (or mingw cygwin) '("-DPIC") '("-fPIC" "-DPIC")))
114(define generate-manifest #f)
115
116(define (libchicken)
117 (string-append "lib"
118 (if (not host-mode)
119 TARGET_LIB_NAME
120 INSTALL_LIB_NAME)))
121
122(define (dynamic-libchicken)
123 (if cygwin
124 (string-append "cyg" INSTALL_LIB_NAME "-0") ; XXX not target
125 (libchicken)))
126
127(define (default-library)
128 (make-pathname library-dir (string-append (libchicken) "-static") library-extension))
129
130(define default-compilation-optimization-options
131 (string-split (if host-mode host-cflags default-cflags)))
132
133(define best-compilation-optimization-options
134 default-compilation-optimization-options)
135
136(define default-linking-optimization-options
137 (string-split (if host-mode INSTALL_LDFLAGS TARGET_LDFLAGS)))
138
139(define best-linking-optimization-options
140 default-linking-optimization-options)
141
142(define extra-features (if host-mode '() (string-split TARGET_FEATURES)))
143
144(define-constant simple-options
145 '(-explicit-use -no-trace -no-warnings -no-usual-integrations -optimize-leaf-routines -unsafe
146 -block -disable-interrupts -fixnum-arithmetic -to-stdout -profile -raw -accumulate-profile
147 -check-syntax -case-insensitive -shared -compile-syntax -no-lambda-info
148 -dynamic -disable-stack-overflow-checks -local
149 -emit-external-prototypes-first -inline -release
150 -analyze-only -keep-shadowed-macros -inline-global -ignore-repository
151 -no-parentheses-synonyms -r7rs-syntax
152 -no-argc-checks -no-bound-checks -no-procedure-checks -no-compiler-syntax
153 -emit-all-import-libraries -no-elevation -module-registration -no-module-registration
154 -no-procedure-checks-for-usual-bindings -regenerate-import-libraries
155 -specialize -strict-types -lfa2 -debug-info
156 -no-procedure-checks-for-toplevel-bindings))
157
158(define-constant complex-options
159 '(-debug -heap-size -nursery -stack-size -compiler -unit -uses -keyword-style
160 -optimize-level -include-path -database-size -extend -prelude -postlude -prologue -epilogue -emit-link-file
161 -inline-limit -profile-name -unroll-limit
162 -emit-inline-file -consult-inline-file
163 -emit-types-file -consult-types-file
164 -feature -debug-level
165 -emit-import-library
166 -module -link
167 -no-feature))
168
169(define-constant shortcuts
170 '((-h "-help")
171 (-s "-shared")
172 (-m "-module")
173 (|-P| "-check-syntax")
174 (-f "-fixnum-arithmetic")
175 (|-D| "-feature")
176 (-i "-case-insensitive")
177 (|-K| "-keyword-style")
178 (|-X| "-extend")
179 (|-J| "-emit-all-import-libraries")
180 (|-M| "-module-registration")
181 (|-N| "-no-module-registration")
182 (-x "-explicit-use")
183 (-u "-unsafe")
184 (-j "-emit-import-library")
185 (-b "-block")
186 (-types "-consult-types-file")))
187
188;; TODO is this up-to-date?
189(define short-options
190 (string->list "PHhsfiENxubvwAOeWkctgSJM") )
191
192
193;;; Variables:
194
195(define scheme-files '())
196(define c-files '())
197(define rc-files '())
198(define generated-c-files '())
199(define generated-rc-files '())
200(define object-files '())
201(define generated-object-files '())
202(define transient-link-files '())
203(define linked-extensions '())
204(define cpp-mode #f)
205(define objc-mode #f)
206(define embedded #f)
207(define inquiry-only #f)
208(define show-cflags #f)
209(define show-ldflags #f)
210(define show-libs #f)
211(define dry-run #f)
212(define gui #f)
213(define deployed #f)
214(define rpath #f)
215(define ignore-repository #f)
216(define show-debugging-help #f)
217
218(define library-dir
219 (if host-mode host-libdir default-libdir))
220
221(define extra-libraries
222 (string-split (if host-mode
223 INSTALL_MORE_STATIC_LIBS
224 TARGET_MORE_STATIC_LIBS)))
225
226(define extra-shared-libraries
227 (if host-mode host-libs default-libs))
228
229(define (library-files)
230 (list (default-library)))
231
232(define (shared-library-files)
233 (list "-l" (if host-mode INSTALL_LIB_NAME TARGET_LIB_NAME)))
234
235(define translate-options '())
236
237(define include-dir
238 (let ((id (if host-mode host-incdir default-incdir)))
239 (and (not (member id '("/usr/include" "")))
240 id) ) )
241
242(define compile-options '())
243
244(define builtin-compile-options
245 (append
246 (if include-dir (list (conc "-I" include-dir)) '())
247 (cond ((get-environment-variable "CHICKEN_C_INCLUDE_PATH") =>
248 (lambda (path)
249 (map (cut string-append "-I" <>) (string-split path ":;"))))
250 (else '()))))
251
252(define compile-only-flag "-c")
253(define translation-optimization-options default-translation-optimization-options)
254(define compilation-optimization-options default-compilation-optimization-options)
255(define linking-optimization-options default-linking-optimization-options)
256
257(define link-options '())
258(define rpath-option (if solaris "-R" "-rpath="))
259
260(define (builtin-link-options)
261 (append
262 (cond (elf
263 (list
264 (conc "-L" library-dir)
265 (conc "-Wl," rpath-option
266 (if deployed
267 "$ORIGIN"
268 (if host-mode
269 host-libdir
270 TARGET_RUN_LIB_HOME)))))
271 (aix
272 (list (conc "-Wl," rpath-option library-dir)))
273 (else
274 (list (conc "-L" library-dir))))
275 (if (and deployed (memq (software-version) '(freebsd openbsd netbsd)))
276 (list "-Wl,-z,origin")
277 '())
278 (cond ((get-environment-variable "CHICKEN_C_LIBRARY_PATH") =>
279 (lambda (path)
280 (map (cut string-append "-L" <>) (string-split path ":;"))))
281 (else '()))))
282
283(define target-filename #f)
284(define verbose #f)
285(define keep-files #f)
286(define translate-only #f)
287(define compile-only #f)
288(define to-stdout #f)
289(define shared #f)
290(define static #f)
291
292
293;;; Locate object files for linking:
294
295(define (repo-path)
296 (if host-mode
297 (repository-path)
298 (destination-repository 'target)))
299
300(define (find-object-file name)
301 (let ((o (make-pathname #f name object-extension))
302 (a (make-pathname #f name library-extension))
303 ;; In setup mode, objects in build dir may also end with "static.o"
304 (static-a (make-pathname #f name static-library-extension))
305 (static-o (make-pathname #f name static-object-extension)))
306 (or (file-exists? a)
307 (file-exists? o)
308 (and (eq? ##sys#setup-mode #t)
309 (or (file-exists? static-a)
310 (file-exists? static-o)))
311 (and (not ignore-repository)
312 (or (chicken.load#find-file a (repo-path))
313 (chicken.load#find-file o (repo-path)))))))
314
315
316;;; Display usage information:
317
318(define (usage)
319 (let ((csc CSC_PROGRAM))
320 (print #<#EOF
321Usage: #{csc} [OPTION ...] [FILENAME ...]
322
323 `#{csc}' is a driver program for the CHICKEN compiler. Files given on the
324 command line are translated, compiled or linked as needed.
325
326 FILENAME is a Scheme source file name with optional extension or a
327 C/C++/Objective-C source, object or library file name with extension. OPTION
328 may be one of the following:
329
330 General options:
331
332 -h -help display this text and exit
333 -v -verbose show compiler notes and tool-invocations
334 -vv display information about translation
335 progress
336 -vvv display information about all compilation
337 stages
338 -version display Scheme compiler version and exit
339 -release display release number and exit
340
341 File and pathname options:
342
343 -o -output-file FILENAME specifies target executable name
344 -I -include-path PATHNAME specifies alternative path for included
345 files
346 -to-stdout write compiler to stdout (implies -t)
347 -s -shared -dynamic generate dynamically loadable shared object
348 file
349
350 Language options:
351
352 -D -DSYMBOL -feature SYMBOL register feature identifier
353 -no-feature SYMBOL disable builtin feature identifier
354 -c++ compile via a C++ source file (.cpp)
355 -objc compile via Objective-C source file (.m)
356
357 Syntax related options:
358
359 -i -case-insensitive don't preserve case of read symbols
360 -K -keyword-style STYLE enable alternative keyword-syntax
361 (prefix, suffix or none)
362 -no-parentheses-synonyms disables list delimiter synonyms
363 -no-symbol-escape disables support for escaped symbols
364 -r7rs-syntax disables the CHICKEN extensions to
365 R7RS syntax
366 -compile-syntax macros are made available at run-time
367 -j -emit-import-library MODULE write compile-time module information into
368 separate file
369 -J -emit-all-import-libraries emit import-libraries for all defined modules
370 -no-compiler-syntax disable expansion of compiler-macros
371 -m -module NAME wrap compiled code in a module
372 -M -module-registration always generate module registration code
373 -N -no-module-registration never generate module registration code
374 (overrides `-M')
375
376 Translation options:
377
378 -x -explicit-use do not use units `library' and `eval' by
379 default
380 -P -check-syntax stop compilation after macro-expansion
381 -A -analyze-only stop compilation after first analysis pass
382
383 Debugging options:
384
385 -w -no-warnings disable warnings
386 -d0 -d1 -d2 -d3 -debug-level NUMBER
387 set level of available debugging information
388 -no-trace disable rudimentary debugging information
389 -debug-info enable debug-information in compiled code for use
390 with an external debugger
391 -profile executable emits profiling information
392 -accumulate-profile executable emits profiling information in
393 append mode
394 -profile-name FILENAME name of the generated profile information
395 file
396 -consult-types-file FILENAME load additional type database
397
398 Optimization options:
399
400 -O -O0 -O1 -O2 -O3 -O4 -O5 -optimize-level NUMBER
401 enable certain sets of optimization options
402 -optimize-leaf-routines enable leaf routine optimization
403 -no-usual-integrations standard procedures may be redefined
404 -u -unsafe disable safety checks
405 -local assume globals are only modified in current
406 file
407 -b -block enable block-compilation
408 -disable-interrupts disable interrupts in compiled code
409 -f -fixnum-arithmetic assume all numbers are fixnums
410 -disable-stack-overflow-checks disables detection of stack-overflows
411 -inline enable inlining
412 -inline-limit LIMIT set inlining threshold
413 -inline-global enable cross-module inlining
414 -specialize perform type-based specialization of primitive calls
415 -oi -emit-inline-file FILENAME generate file with globally inlinable
416 procedures (implies -inline -local)
417 -consult-inline-file FILENAME explicitly load inline file
418 -ot -emit-types-file FILENAME write type-declaration information into file
419 -no-argc-checks disable argument count checks
420 -no-bound-checks disable bound variable checks
421 -no-procedure-checks disable procedure call checks
422 -no-procedure-checks-for-usual-bindings
423 disable procedure call checks only for usual
424 bindings
425 -no-procedure-checks-for-toplevel-bindings
426 disable procedure call checks for toplevel
427 bindings
428 -strict-types assume variable do not change their type
429 -lfa2 perform additional lightweight flow-analysis pass
430 -unroll-limit LIMIT specifies inlining limit for self-recursive calls
431
432 Configuration options:
433
434 -unit NAME compile file as a library unit
435 -uses NAME declare library unit as used.
436 -heap-size NUMBER specifies heap-size of compiled executable
437 -nursery NUMBER -stack-size NUMBER
438 specifies nursery size of compiled
439 executable
440 -X -extend FILENAME load file before compilation commences
441 -prelude EXPRESSION add expression to beginning of source file
442 -postlude EXPRESSION add expression to end of source file
443 -prologue FILENAME include file before main source file
444 -epilogue FILENAME include file after main source file
445
446 -e -embedded compile as embedded
447 (don't generate `main()')
448 -gui compile as GUI application
449 -link NAME link extension with compiled executable
450 (implies -uses)
451 -R -require-extension NAME require extension and import in compiled
452 code
453 -dll -library compile multiple units into a dynamic
454 library
455 -libdir DIRECTORY override directory for runtime library
456
457 Options to other passes:
458
459 -C OPTION pass option to C compiler
460 -L OPTION pass option to linker
461 -I<DIR> pass \"-I<DIR>\" to C compiler
462 (add include path)
463 -L<DIR> pass \"-L<DIR>\" to linker
464 (add library path)
465 -k keep intermediate files
466 -c stop after compilation to object files
467 -t stop after translation to C
468 -cc COMPILER select other C compiler than the default
469 -cxx COMPILER select other C++ compiler than the default
470 -ld COMPILER select other linker than the default
471 -static link with static CHICKEN libraries and
472 extensions (if possible)
473 -F<DIR> pass \"-F<DIR>\" to C compiler
474 (add framework header path on Mac OS X)
475 -framework NAME passed to linker on Mac OS X
476 -rpath PATHNAME add directory to runtime library search path
477 -Wl,... pass linker options
478 -strip strip resulting binary
479
480 Inquiry options:
481
482 -home show home-directory (where support files go)
483 -cflags show required C-compiler flags and exit
484 -ldflags show required linker flags and exit
485 -libs show required libraries and exit
486 -cc-name show name of default C compiler used
487 -cxx-name show name of default C++ compiler used
488 -ld-name show name of default linker used
489 -dry-run just show commands executed, don't run them
490 (implies `-v')
491
492 Obscure options:
493
494 -debug MODES display debugging output for the given modes
495 -compiler PATHNAME use other compiler than default `chicken'
496 -raw do not generate implicit init- and exit code
497 -emit-external-prototypes-first
498 emit prototypes for callbacks before foreign
499 declarations
500 -regenerate-import-libraries emit import libraries even when unchanged
501 -ignore-repository do not refer to repository for extensions
502 -keep-shadowed-macros do not remove shadowed macro
503 -host compile for host when configured for
504 cross-compiling
505 -private-repository load extensions from executable path
506 -deployed link support file to be used from a deployed
507 executable (sets `rpath' accordingly, if supported
508 on this platform)
509 -no-elevation embed manifest on Windows to supress elevation
510 warnings for programs named `install' or `setup'
511
512 Options can be collapsed if unambiguous, so
513
514 -vkfO
515
516 is the same as
517
518 -v -k -fixnum-arithmetic -optimize
519
520 The contents of the environment variable CSC_OPTIONS are implicitly passed to
521 every invocation of `#{csc}'.
522
523EOF
524;| (for emacs font-lock)
525 ) ) )
526
527
528;;; Parse arguments:
529
530(define (run args)
531
532 (define (t-options . os)
533 (set! translate-options (append translate-options os)) )
534
535 (define (check o r . n)
536 (unless (>= (length r) (optional n 1))
537 (stop "not enough arguments to option `~A'" o) ) )
538
539 (define (shared-build lib)
540 (set! translate-options (cons* "-feature" "chicken-compile-shared" translate-options))
541 (set! compile-options (append pic-options '("-DC_SHARED") compile-options))
542 (set! link-options
543 (append
544 (cond
545 (osx (if lib '("-dynamiclib") '("-bundle" "-headerpad_max_install_names")))
546 (else '("-shared"))) link-options))
547 (set! shared #t) )
548
549 (define (use-private-repository)
550 (set! compile-options (cons "-DC_PRIVATE_REPOSITORY" compile-options)))
551
552 (define (generate-target-filename source-filename)
553 (pathname-replace-extension
554 source-filename
555 (cond (shared shared-library-extension)
556 (compile-only object-extension)
557 (else executable-extension))))
558
559 (let loop ((args args))
560 (cond [(null? args)
561 ;; Builtin search directory options do not override explicit options
562 (set! compile-options (append compile-options builtin-compile-options))
563 (set! link-options (append link-options (builtin-link-options)))
564 ;;
565 (when inquiry-only
566 (when show-cflags (print* (compiler-options) #\space))
567 (when show-ldflags (print* (linker-options) #\space))
568 (when show-libs (print* (linker-libraries) #\space))
569 (newline)
570 (exit) )
571 (when (and compile-only
572 (> (+ (length scheme-files)
573 (length c-files))
574 1))
575 (stop "the `-c' option cannot be used in combination with multiple input files"))
576 (cond ((null? scheme-files)
577 (when (and (null? c-files)
578 (null? object-files))
579 (when show-debugging-help
580 (exec translator (cons "bogus.scm" translate-options)))
581 (stop "no source files specified") )
582 (unless target-filename
583 (set! target-filename
584 (generate-target-filename
585 (last (if (null? c-files) object-files c-files))))))
586 (else
587 (when (and shared (not embedded))
588 (set! translate-options (cons "-dynamic" translate-options)) )
589 (unless target-filename
590 (set! target-filename
591 (generate-target-filename (first scheme-files))))
592 (run-translation)))
593 (unless translate-only
594 (run-compilation)
595 (unless compile-only
596 (when (pair? linked-extensions)
597 (set! object-files ; add objects from linked extensions
598 (append (filter-map find-object-file linked-extensions) object-files)))
599 (when (member target-filename scheme-files)
600 (fprintf (current-error-port)
601 "Warning: output file will overwrite source file `~A' - renaming source to `~A.old'~%"
602 target-filename target-filename)
603 (exec (if windows-shell "move" "mv")
604 (list target-filename
605 (string-append target-filename ".old"))))
606 (run-linking)) ) ]
607 [else
608 (let* ([arg (car args)]
609 [rest (cdr args)]
610 [s (string->symbol arg)] )
611 (case s
612 [(-help --help)
613 (usage)
614 (exit) ]
615 [(-release)
616 (print (chicken-version))
617 (exit) ]
618 [(-version)
619 (exec translator '("-version"))
620 (exit)]
621 [(-c++)
622 (set! cpp-mode #t)
623 (when osx (set! compile-options (cons "-no-cpp-precomp" compile-options))) ]
624 [(-objc)
625 (set! objc-mode #t) ]
626 [(-static)
627 (set! translate-options (cons "-static" translate-options))
628 (set! static #t)]
629 [(-cflags)
630 (set! inquiry-only #t)
631 (set! show-cflags #t) ]
632 [(-ldflags)
633 (set! inquiry-only #t)
634 (set! show-ldflags #t) ]
635 [(-cc-name) (print compiler) (exit 0)]
636 [(-cxx-name) (print c++-compiler) (exit 0)]
637 [(-ld-name) (print linker) (exit 0)]
638 [(-home) (print home) (exit 0)]
639 [(-libs)
640 (set! inquiry-only #t)
641 (set! show-libs #t) ]
642 ((-v -verbose)
643 (when (number? verbose)
644 (set! compile-options (cons* "-v" "-Q" compile-options))
645 (set! link-options (cons "-v" link-options)) )
646 (t-options "-verbose")
647 (if verbose
648 (set! verbose 2)
649 (set! verbose #t)) )
650 [(-w -no-warnings)
651 (set! compile-options (cons "-w" compile-options))
652 (t-options "-no-warnings") ]
653 [(|-A| -analyze-only)
654 (set! translate-only #t)
655 (t-options "-analyze-only") ]
656 [(|-P| -check-syntax)
657 (set! translate-only #t)
658 (t-options "-check-syntax") ]
659 [(-k) (set! keep-files #t)]
660 [(-c) (set! compile-only #t)]
661 [(-t) (set! translate-only #t)]
662 [(-e -embedded)
663 (set! embedded #t)
664 (set! compile-options (cons "-DC_EMBEDDED" compile-options)) ]
665 [(-link)
666 (check s rest)
667 (t-options "-link" (car rest))
668 (set! linked-extensions
669 (append linked-extensions (string-split (car rest) ", ")))
670 (set! rest (cdr rest))]
671 ((-libdir)
672 (check s rest)
673 (set! library-dir (car rest))
674 (set! rest (cdr rest)))
675 [(-require-extension -R)
676 (check s rest)
677 (t-options "-require-extension" (car rest))
678 (set! rest (cdr rest)) ]
679 ((-private-repository)
680 (use-private-repository))
681 ((-ignore-repository)
682 (set! ignore-repository #t)
683 (t-options arg))
684 ((-setup-mode)
685 (set! ##sys#setup-mode #t)
686 (t-options arg))
687 ((-no-elevation)
688 (set! generate-manifest #t))
689 [(-gui)
690 (set! gui #t)
691 (set! compile-options (cons "-DC_GUI" compile-options))
692 (when mingw
693 (set! object-files
694 (cons (make-pathname
695 host-sharedir "chicken.rc"
696 object-extension)
697 object-files))
698 (set! link-options
699 (cons* "-lkernel32" "-luser32" "-lgdi32" "-mwindows"
700 link-options)))]
701 ((-deployed)
702 (set! deployed #t))
703 [(-framework)
704 (check s rest)
705 (when osx
706 (set! link-options (cons* "-framework" (car rest) link-options)) )
707 (set! rest (cdr rest)) ]
708 [(-o -output-file)
709 (check s rest)
710 (let ([fn (car rest)])
711 (set! rest (cdr rest))
712 (set! target-filename fn) ) ]
713 [(|-O| |-O1|) (set! rest (cons* "-optimize-level" "1" rest))]
714 [(|-O0|) (set! rest (cons* "-optimize-level" "0" rest))]
715 [(|-O2|) (set! rest (cons* "-optimize-level" "2" rest))]
716 [(|-O3|) (set! rest (cons* "-optimize-level" "3" rest))]
717 [(|-O4|) (set! rest (cons* "-optimize-level" "4" rest))]
718 [(|-O5|)
719 (set! rest (cons* "-optimize-level" "5" rest))]
720 [(|-d0|) (set! rest (cons* "-debug-level" "0" rest))]
721 [(|-d1|) (set! rest (cons* "-debug-level" "1" rest))]
722 [(|-d2|) (set! rest (cons* "-debug-level" "2" rest))]
723 [(|-d3|) (set! rest (cons* "-debug-level" "3" rest))]
724 ((-debug)
725 (check s rest)
726 (t-options arg (car rest))
727 (when (memv #\h (string->list (car rest)))
728 (set! show-debugging-help #t)
729 (set! translate-only #t))
730 (set! rest (cdr rest)))
731 [(-dry-run)
732 (set! verbose #t)
733 (set! dry-run #t)]
734 [(-s -shared -dynamic)
735 (shared-build #f) ]
736 [(-dll -library)
737 (shared-build #t) ]
738 [(-compiler)
739 (check s rest)
740 (set! translator (car rest))
741 (set! rest (cdr rest)) ]
742 [(-cc)
743 (check s rest)
744 (set! compiler (car rest))
745 (set! rest (cdr rest)) ]
746 [(-cxx)
747 (check s rest)
748 (set! c++-compiler (car rest))
749 (set! rest (cdr rest)) ]
750 [(-ld)
751 (check s rest)
752 (set! linker (car rest))
753 (set! rest (cdr rest)) ]
754 [(|-I|)
755 (check s rest)
756 (set! rest (cons* "-include-path" (car rest) (cdr rest))) ]
757 [(|-C|)
758 (check s rest)
759 (set! compile-options (append compile-options (string-split (car rest))))
760 (set! rest (cdr rest)) ]
761 [(-strip)
762 (set! link-options (append link-options (list "-s")))]
763 [(|-L|)
764 (check s rest)
765 (set! link-options (append link-options (string-split (car rest))))
766 (set! rest (cdr rest)) ]
767 [(-rpath)
768 (check s rest)
769 (set! rpath (car rest))
770 (when (and (memq (build-platform) '(gnu clang))
771 (not mingw) (not osx))
772 (set! link-options
773 (append link-options (list (string-append "-Wl," rpath-option rpath)))) )
774 (set! rest (cdr rest)) ]
775 [(-host) #f]
776 ((-oi)
777 (check s rest)
778 (t-options "-emit-inline-file" (car rest))
779 (set! rest (cdr rest)))
780 ((-ot)
781 (check s rest)
782 (t-options "-emit-types-file" (car rest))
783 (set! rest (cdr rest)))
784 [(-)
785 (set! scheme-files (append scheme-files '("-")))
786 (unless target-filename
787 (set! target-filename (make-pathname #f "a" executable-extension)))]
788 [else
789 (when (eq? s '-to-stdout)
790 (set! to-stdout #t)
791 (set! translate-only #t) )
792 (when (memq s '(-optimize-level -benchmark-mode))
793 (set! compilation-optimization-options best-compilation-optimization-options)
794 (set! linking-optimization-options best-linking-optimization-options) )
795 (cond [(assq s shortcuts) => (lambda (a) (set! rest (cons (cadr a) rest)))]
796 [(memq s simple-options) (t-options arg)]
797 ((memq s complex-options)
798 (check s rest)
799 (t-options arg (car rest))
800 (set! rest (cdr rest)))
801 [(and (> (string-length arg) 2) (string=? "-:" (substring arg 0 2)))
802 (t-options arg) ]
803 [(and (> (string-length arg) 1)
804 (char=? #\- (string-ref arg 0)) )
805 (cond [(char=? #\L (string-ref arg 1))
806 (when (char-whitespace? (string-ref arg 2))
807 (error "bad -L argument, <DIR> starts with whitespace" arg))
808 (set! link-options (append link-options (list arg))) ]
809 [(char=? #\I (string-ref arg 1))
810 (when (char-whitespace? (string-ref arg 2))
811 (error "bad -I argument: <DIR> starts with whitespace" arg))
812 (set! compile-options (append compile-options (list arg))) ]
813 [(char=? #\D (string-ref arg 1))
814 (t-options "-feature" (substring arg 2)) ]
815 [(char=? #\F (string-ref arg 1))
816 (when osx
817 (set! compile-options (append compile-options (list arg))) ) ]
818 [(and (> (string-length arg) 3) (string=? "-Wl," (substring arg 0 4)))
819 (set! link-options (append link-options (list arg))) ]
820 [(> (string-length arg) 2)
821 (let ([opts (cdr (string->list arg))])
822 (cond ((null? (lset-difference/eq? opts short-options))
823 (set! rest
824 (append (map (lambda (o)
825 (string-append "-" (string o))) opts)
826 rest) ))
827 ((char=? #\l (car opts))
828 (stop "invalid option `~A' - did you mean `-L -l<library>'?" arg))
829 (else (stop "invalid option `~A'" arg) ) )) ]
830 [else (stop "invalid option `~A'" s)] ) ]
831 [(file-exists? arg)
832 (let-values ([(dirs name ext) (decompose-pathname arg)])
833 (cond [(not ext)
834 (set! scheme-files (append scheme-files (list arg)))]
835 [(member ext '("h" "c"))
836 (set! c-files (append c-files (list arg))) ]
837 ((string-ci=? ext "rc")
838 (set! rc-files (append rc-files (list arg))) )
839 [(member ext '("cpp" "C" "cc" "cxx" "hpp"))
840 (when osx (set! compile-options (cons "-no-cpp-precomp" compile-options)))
841 (set! cpp-mode #t)
842 (set! c-files (append c-files (list arg))) ]
843 [(member ext '("m" "M" "mm"))
844 (set! objc-mode #t)
845 (set! c-files (append c-files (list arg))) ]
846 [(or (string=? ext object-extension)
847 (string=? ext library-extension) )
848 (set! object-files (append object-files (list arg))) ]
849 [else (set! scheme-files (append scheme-files (list arg)))] ) ) ]
850 [else
851 (let ([f2 (string-append arg ".scm")])
852 (if (file-exists? f2)
853 (set! rest (cons f2 rest))
854 (stop "file `~A' does not exist" arg) ) ) ] ) ] )
855 (loop rest) ) ] ) ) )
856
857
858;;; Translate all Scheme files:
859
860(define (run-translation)
861 (for-each
862 (lambda (f)
863 (let* ((sf (if (= 1 (length scheme-files))
864 target-filename
865 f))
866 (fc (pathname-replace-extension
867 sf
868 (cond (cpp-mode "cpp")
869 (objc-mode "m")
870 (else "c") ) ) ) )
871 (when (member fc c-files)
872 (stop "C file generated from `~a' will overwrite explicitly given source file `~a'"
873 f fc))
874 (exec
875 translator
876 (cons* f
877 (append
878 (if to-stdout
879 '("-to-stdout")
880 `("-output-file" ,fc) )
881 (if (##sys#debug-mode?)
882 '("-:d")
883 '())
884 extra-features
885 translate-options
886 (if (and static
887 (not (member "-emit-link-file"
888 translate-options)))
889 (list "-emit-link-file"
890 (pathname-replace-extension fc "link"))
891 '())
892 (cond (cpp-mode '("-feature" "chicken-scheme-to-c++"))
893 (objc-mode '("-feature" "chicken-scheme-to-objc"))
894 (else '()))
895 translation-optimization-options ) ) )
896 (when (and static compile-only)
897 (set! transient-link-files
898 (cons (pathname-replace-extension f "link")
899 transient-link-files)))
900 (set! c-files (append (list fc) c-files))
901 (set! generated-c-files (append (list fc) generated-c-files))))
902 scheme-files))
903
904
905;;; Compile all C/C++ and .rc files:
906
907(define (run-compilation)
908 (let ((ofiles '()))
909 (for-each
910 (lambda (f)
911 (let ((fo (if (and compile-only
912 target-filename
913 (= 1 (length c-files)))
914 target-filename
915 (pathname-replace-extension f object-extension))))
916 (when (member fo object-files)
917 (stop "object file generated from `~a' will overwrite explicitly given object file `~a'"
918 f fo))
919 (exec (cond (cpp-mode c++-compiler)
920 (else compiler) )
921 (cons* f
922 compile-output-flag fo
923 compile-only-flag
924 (append (if (and cpp-mode (string=? "g++" c++-compiler)) ; XXX This is somewhat hacky - g++ might not be *named* g++
925 '("-Wno-write-strings")
926 '())
927 (compiler-options)) ) )
928 (set! generated-object-files (cons fo generated-object-files))
929 (set! ofiles (cons fo ofiles))))
930 c-files)
931 (when (and generate-manifest (eq? 'windows (software-type)))
932 (let ((rcf (pathname-replace-extension target-filename "rc")))
933 (create-win-manifest (pathname-file target-filename) rcf)
934 (set! rc-files (cons rcf rc-files))
935 (set! generated-rc-files (cons rcf generated-rc-files))))
936 (for-each
937 (lambda (f)
938 (let ((fo (string-append f "." object-extension)))
939 (exec rc-compiler (list f fo))
940 (set! generated-object-files (cons fo generated-object-files))
941 (set! ofiles (cons fo ofiles))))
942 rc-files)
943 (set! object-files (append (reverse ofiles) object-files)) ; put generated object files first
944 (unless keep-files
945 (for-each $delete-file generated-c-files)
946 (for-each $delete-file generated-rc-files))))
947
948(define (compiler-options)
949 (append
950 compilation-optimization-options
951 compile-options) )
952
953
954;;; Link object files and libraries:
955
956(define (run-linking)
957 (set! object-files
958 (collect-linked-objects object-files generated-object-files))
959 (exec (cond (cpp-mode c++-linker)
960 (else linker) )
961 (append
962 object-files
963 (list link-output-flag target-filename)
964 (linker-options)
965 (linker-libraries) ) )
966 (when (and osx host-mode)
967 (let ((lib (string-append (libchicken) ".dylib")))
968 (exec POSTINSTALL_PROGRAM
969 (list "-change" lib
970 (if deployed
971 (make-pathname "@executable_path" lib)
972 (make-pathname (or rpath
973 (if host-mode
974 host-libdir
975 TARGET_RUN_LIB_HOME))
976 lib))
977 target-filename))))
978 (unless keep-files
979 (for-each $delete-file
980 (append generated-object-files
981 transient-link-files))))
982
983(define (collect-linked-objects ofiles gen-ofiles)
984 (define (locate-link-file o)
985 (let* ((p (pathname-strip-extension o))
986 ;; Also strip "static.o" extension when in setup mode:
987 (f (if ##sys#setup-mode (string-chomp p ".static") p)))
988 (file-exists? (make-pathname #f f "link"))))
989 (define (locate-objects libs)
990 (map (lambda (id)
991 (or (find-object-file id)
992 (stop "could not find linked extension: ~A" id)))
993 (map ->string libs)))
994 (let loop ((os ofiles) (os2 ofiles))
995 (cond ((null? os)
996 (delete-duplicates (reverse os2) string=?))
997 ((or static (not (member (car os) gen-ofiles)))
998 (let* ((lfile (locate-link-file (car os)))
999 (newos (if lfile
1000 (locate-objects (with-input-from-file lfile read))
1001 '())))
1002 (loop (append newos (cdr os)) (append newos os2))))
1003 (else (loop (cdr os) (cons (car os) os2))))))
1004
1005(define (copy-files from to)
1006 (exec (if windows-shell "copy" "cp")
1007 (append (if windows-shell '("/Y") '())
1008 (list from to))))
1009
1010(define (linker-options)
1011 (append linking-optimization-options link-options) )
1012
1013(define (linker-libraries)
1014 (append
1015 (if static
1016 (library-files)
1017 (shared-library-files))
1018 (if static
1019 extra-libraries
1020 extra-shared-libraries)))
1021
1022
1023;;; Helper procedures:
1024
1025;; Simpler replacement for SRFI-13's string-any
1026(define (string-any criteria s)
1027 (let ((end (string-length s)))
1028 (let lp ((i 0))
1029 (let ((c (string-ref s i))
1030 (i1 (+ i 1)))
1031 (if (= i1 end) (criteria c)
1032 (or (criteria c)
1033 (lp i1)))))))
1034
1035(define (exec prog args)
1036 ;; NOTE: We construct a command line for debugging purposes, but it
1037 ;; does not 100% represent what gets executed.
1038 (let ((cmdline (string-intersperse (map quotewrap (cons prog args)) " ")))
1039 (when verbose
1040 (print cmdline))
1041 (unless dry-run
1042 (let*-values (((pid) (process-run prog args))
1043 ((pid success? exit-code) (process-wait pid)))
1044 (when (or (not success?) (not (zero? exit-code)))
1045 (printf "\nError: shell command terminated with non-zero exit status ~S: ~A~%" exit-code cmdline)
1046 (exit exit-code))))))
1047
1048(define ($delete-file str)
1049 (when verbose
1050 (print "rm " str) )
1051 (unless dry-run (delete-file str) ))
1052
1053(define (create-win-manifest prg rcfname)
1054 (when verbose (print "generating " rcfname))
1055 (with-output-to-file rcfname
1056 (lambda ()
1057 (print #<#EOF
10581 24 MOVEABLE PURE
1059BEGIN
1060 "<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>\r\n"
1061 "<assembly xmlns=""urn:schemas-microsoft-com:asm.v1"" manifestVersion=""1.0"">\r\n"
1062 " <assemblyIdentity version=""1.0.0.0"" processorArchitecture=""*"" name=""#{prg}"" type=""win32""/>\r\n"
1063 " <ms_asmv2:trustInfo xmlns:ms_asmv2=""urn:schemas-microsoft-com:asm.v2"">\r\n"
1064 " <ms_asmv2:security>\r\n"
1065 " <ms_asmv2:requestedPrivileges>\r\n"
1066 " <ms_asmv2:requestedExecutionLevel level=""asInvoker"" uiAccess=""false""/>\r\n"
1067 " </ms_asmv2:requestedPrivileges>\r\n"
1068 " </ms_asmv2:security>\r\n"
1069 " </ms_asmv2:trustInfo>\r\n"
1070 "</assembly>\r\n"
1071END
1072EOF
1073) ) ) )
1074
1075
1076;;; Run it:
1077
1078(run
1079 (append
1080 (string-split (or (get-environment-variable "CSC_OPTIONS") ""))
1081 arguments))
1082
1083)