~ chicken-core (chicken-5) /csc.scm


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