~ chicken-core (master) /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.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 -clustering -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    -clustering                    combine groups of local procedures into dispatch
 430                                     loop
 431    -lfa2                          perform additional lightweight flow-analysis pass
 432    -unroll-limit LIMIT          specifies inlining limit for self-recursive calls
 433
 434  Configuration options:
 435
 436    -unit NAME                     compile file as a library unit
 437    -uses NAME                     declare library unit as used.
 438    -heap-size NUMBER              specifies heap-size of compiled executable
 439    -nursery NUMBER  -stack-size NUMBER
 440                                   specifies nursery size of compiled
 441                                   executable
 442    -X -extend FILENAME            load file before compilation commences
 443    -prelude EXPRESSION            add expression to beginning of source file
 444    -postlude EXPRESSION           add expression to end of source file
 445    -prologue FILENAME             include file before main source file
 446    -epilogue FILENAME             include file after main source file
 447
 448    -e  -embedded                  compile as embedded
 449                                    (don't generate `main()')
 450    -gui                           compile as GUI application
 451    -link NAME                     link extension with compiled executable
 452                                    (implies -uses)
 453    -R  -require-extension NAME    require extension and import in compiled
 454                                    code
 455    -dll -library                  compile multiple units into a dynamic
 456                                    library
 457    -libdir DIRECTORY              override directory for runtime library
 458
 459  Options to other passes:
 460
 461    -C OPTION                      pass option to C compiler
 462    -L OPTION                      pass option to linker
 463    -I<DIR>                        pass \"-I<DIR>\" to C compiler
 464                                    (add include path)
 465    -L<DIR>                        pass \"-L<DIR>\" to linker
 466                                    (add library path)
 467    -k                             keep intermediate files
 468    -c                             stop after compilation to object files
 469    -t                             stop after translation to C
 470    -cc COMPILER                   select other C compiler than the default
 471    -cxx COMPILER                  select other C++ compiler than the default
 472    -ld COMPILER                   select other linker than the default
 473    -static                        link with static CHICKEN libraries and
 474                                    extensions (if possible)
 475    -F<DIR>                        pass \"-F<DIR>\" to C compiler
 476                                    (add framework header path on Mac OS X)
 477    -framework NAME                passed to linker on Mac OS X
 478    -rpath PATHNAME                add directory to runtime library search path
 479    -Wl,...                        pass linker options
 480    -strip                         strip resulting binary
 481
 482  Inquiry options:
 483
 484    -home                          show home-directory (where support files go)
 485    -cflags                        show required C-compiler flags and exit
 486    -ldflags                       show required linker flags and exit
 487    -libs                          show required libraries and exit
 488    -cc-name                       show name of default C compiler used
 489    -cxx-name                      show name of default C++ compiler used
 490    -ld-name                       show name of default linker used
 491    -dry-run                       just show commands executed, don't run them
 492                                    (implies `-v')
 493
 494  Obscure options:
 495
 496    -debug MODES                   display debugging output for the given modes
 497    -compiler PATHNAME             use other compiler than default `chicken'
 498    -raw                           do not generate implicit init- and exit code
 499    -emit-external-prototypes-first
 500                                   emit prototypes for callbacks before foreign
 501                                    declarations
 502    -regenerate-import-libraries   emit import libraries even when unchanged
 503    -ignore-repository             do not refer to repository for extensions
 504    -keep-shadowed-macros          do not remove shadowed macro
 505    -host                          compile for host when configured for
 506                                    cross-compiling
 507    -private-repository            load extensions from executable path
 508    -deployed                      link support file to be used from a deployed
 509                                    executable (sets `rpath' accordingly, if supported
 510                                    on this platform)
 511    -no-elevation                  embed manifest on Windows to supress elevation
 512                                    warnings for programs named `install' or `setup'
 513
 514  Options can be collapsed if unambiguous, so
 515
 516    -vkfO
 517
 518  is the same as
 519
 520    -v -k -fixnum-arithmetic -optimize
 521
 522  The contents of the environment variable CSC_OPTIONS are implicitly passed to
 523  every invocation of `#{csc}'.
 524
 525EOF
 526;|        (for emacs font-lock)
 527  ) ) )
 528
 529
 530;;; Parse arguments:
 531
 532(define (run args)
 533
 534  (define (t-options . os)
 535    (set! translate-options (append translate-options os)) )
 536
 537  (define (check o r . n)
 538    (unless (>= (length r) (optional n 1))
 539      (stop "not enough arguments to option `~A'" o) ) )
 540
 541  (define (shared-build lib)
 542    (set! translate-options (cons* "-feature" "chicken-compile-shared" translate-options))
 543    (set! compile-options (append pic-options '("-DC_SHARED") compile-options))
 544    (set! link-options
 545      (append
 546	(cond
 547          (osx (if lib '("-dynamiclib") '("-bundle" "-headerpad_max_install_names")))
 548          (else '("-shared"))) link-options))
 549    (set! shared #t) )
 550
 551  (define (use-private-repository)
 552    (set! compile-options (cons "-DC_PRIVATE_REPOSITORY" compile-options)))
 553
 554  (define (generate-target-filename source-filename)
 555    (pathname-replace-extension
 556     source-filename
 557     (cond (shared shared-library-extension)
 558	   (compile-only object-extension)
 559	   (else executable-extension))))
 560
 561  (let loop ((args args))
 562    (cond [(null? args)
 563	   ;; Builtin search directory options do not override explicit options
 564           (set! compile-options (append compile-options builtin-compile-options))
 565           (set! link-options (append link-options (builtin-link-options)))
 566	   ;;
 567	   (when inquiry-only
 568	     (when show-cflags (print* (compiler-options) #\space))
 569	     (when show-ldflags (print* (linker-options) #\space))
 570	     (when show-libs (print* (linker-libraries) #\space))
 571	     (newline)
 572	     (exit) )
 573	   (when (and compile-only
 574		      (> (+ (length scheme-files)
 575			    (length c-files))
 576			 1))
 577	     (stop "the `-c' option cannot be used in combination with multiple input files"))
 578	   (cond ((null? scheme-files)
 579		  (when (and (null? c-files)
 580			     (null? object-files))
 581		    (when show-debugging-help
 582		      (exec translator (cons "bogus.scm" translate-options)))
 583		    (stop "no source files specified") )
 584		  (unless target-filename
 585		    (set! target-filename
 586		      (generate-target-filename
 587		       (last (if (null? c-files) object-files c-files))))))
 588		 (else
 589		  (when (and shared (not embedded))
 590		    (set! translate-options (cons "-dynamic" translate-options)) )
 591		  (unless target-filename
 592		    (set! target-filename
 593		      (generate-target-filename (first scheme-files))))
 594		  (run-translation)))
 595	   (unless translate-only
 596	     (run-compilation)
 597	     (unless compile-only
 598	       (when (pair? linked-extensions)
 599		 (set! object-files ; add objects from linked extensions
 600		   (append (filter-map find-object-file linked-extensions) object-files)))
 601	       (when (member target-filename scheme-files)
 602		 (fprintf (current-error-port)
 603                          "Warning: output file will overwrite source file `~A' - renaming source to `~A.old'~%"
 604			 target-filename target-filename)
 605		 (exec (if windows-shell "move" "mv")
 606		       (list target-filename
 607		             (string-append target-filename ".old"))))
 608	       (run-linking)) ) ]
 609	  [else
 610	   (let* ([arg (car args)]
 611		  [rest (cdr args)]
 612		  [s (string->symbol arg)] )
 613	     (case s
 614	       [(-help --help)
 615		(usage)
 616		(exit) ]
 617	       [(-release)
 618		(print (chicken-version))
 619		(exit) ]
 620	       [(-version)
 621		(exec translator '("-version"))
 622		(exit)]
 623	       [(-c++)
 624		(set! cpp-mode #t)
 625		(when osx (set! compile-options (cons "-no-cpp-precomp" compile-options))) ]
 626	       [(-objc)
 627		(set! objc-mode #t) ]
 628	       [(-static)
 629		(set! translate-options (cons "-static" translate-options))
 630		(set! static #t)]
 631	       [(-cflags)
 632		(set! inquiry-only #t)
 633		(set! show-cflags #t) ]
 634	       [(-ldflags)
 635		(set! inquiry-only #t)
 636		(set! show-ldflags #t) ]
 637	       [(-cc-name) (print compiler) (exit 0)]
 638	       [(-cxx-name) (print c++-compiler) (exit 0)]
 639	       [(-ld-name) (print linker) (exit 0)]
 640	       [(-home) (print home) (exit 0)]
 641	       [(-libs)
 642		(set! inquiry-only #t)
 643		(set! show-libs #t) ]
 644	       ((-v -verbose)
 645		(when (number? verbose)
 646		  (set! compile-options (cons* "-v" "-Q" compile-options))
 647		  (set! link-options (cons "-v" link-options)) )
 648		(t-options "-verbose")
 649		(if verbose
 650		    (set! verbose 2)
 651		    (set! verbose #t)) )
 652	       [(-w -no-warnings)
 653		(set! compile-options (cons "-w" compile-options))
 654		(t-options "-no-warnings") ]
 655	       [(|-A| -analyze-only)
 656		(set! translate-only #t)
 657		(t-options "-analyze-only") ]
 658	       [(|-P| -check-syntax)
 659		(set! translate-only #t)
 660		(t-options "-check-syntax") ]
 661	       [(-k) (set! keep-files #t)]
 662	       [(-c) (set! compile-only #t)]
 663	       [(-t) (set! translate-only #t)]
 664	       [(-e -embedded)
 665		(set! embedded #t)
 666		(set! compile-options (cons "-DC_EMBEDDED" compile-options)) ]
 667	       [(-link)
 668		(check s rest)
 669		(t-options "-link" (car rest))
 670		(set! linked-extensions
 671		  (append linked-extensions (string-split (car rest) ", ")))
 672		(set! rest (cdr rest))]
 673               ((-libdir)
 674                (check s rest)
 675                (set! library-dir (car rest))
 676                (set! rest (cdr rest)))
 677	       [(-require-extension -R)
 678		(check s rest)
 679		(t-options "-require-extension" (car rest))
 680		(set! rest (cdr rest)) ]
 681	       ((-private-repository)
 682		(use-private-repository))
 683	       ((-ignore-repository)
 684		(set! ignore-repository #t)
 685		(t-options arg))
 686	       ((-setup-mode)
 687		(set! ##sys#setup-mode #t)
 688		(t-options arg))
 689	       ((-no-elevation)
 690		(set! generate-manifest #t))
 691	       [(-gui)
 692		(set! gui #t)
 693		(set! compile-options (cons "-DC_GUI" compile-options))
 694		(when mingw
 695		  (set! object-files
 696		    (cons (make-pathname
 697			   host-sharedir "chicken.rc"
 698			   object-extension)
 699			  object-files))
 700		  (set! link-options
 701		    (cons* "-lkernel32" "-luser32" "-lgdi32" "-mwindows"
 702			   link-options)))]
 703	       ((-deployed)
 704		(set! deployed #t))
 705	       [(-framework)
 706		(check s rest)
 707		(when osx
 708		  (set! link-options (cons* "-framework" (car rest) link-options)) )
 709		(set! rest (cdr rest)) ]
 710	       [(-o -output-file)
 711		(check s rest)
 712		(let ([fn (car rest)])
 713		  (set! rest (cdr rest))
 714		  (set! target-filename fn) ) ]
 715	       [(|-O| |-O1|) (set! rest (cons* "-optimize-level" "1" rest))]
 716	       [(|-O0|) (set! rest (cons* "-optimize-level" "0" rest))]
 717	       [(|-O2|) (set! rest (cons* "-optimize-level" "2" rest))]
 718	       [(|-O3|) (set! rest (cons* "-optimize-level" "3" rest))]
 719	       [(|-O4|) (set! rest (cons* "-optimize-level" "4" rest))]
 720	       [(|-O5|)
 721		(set! rest (cons* "-optimize-level" "5" rest))]
 722	       [(|-d0|) (set! rest (cons* "-debug-level" "0" rest))]
 723	       [(|-d1|) (set! rest (cons* "-debug-level" "1" rest))]
 724	       [(|-d2|) (set! rest (cons* "-debug-level" "2" rest))]
 725	       [(|-d3|) (set! rest (cons* "-debug-level" "3" rest))]
 726	       ((-debug)
 727		(check s rest)
 728		(t-options arg (car rest))
 729		(when (memv #\h (string->list (car rest)))
 730		  (set! show-debugging-help #t)
 731		  (set! translate-only #t))
 732		(set! rest (cdr rest)))
 733	       [(-dry-run)
 734		(set! verbose #t)
 735		(set! dry-run #t)]
 736	       [(-s -shared -dynamic)
 737		(shared-build #f) ]
 738	       [(-dll -library)
 739		(shared-build #t) ]
 740	       [(-compiler)
 741		(check s rest)
 742		(set! translator (car rest))
 743		(set! rest (cdr rest)) ]
 744	       [(-cc)
 745		(check s rest)
 746		(set! compiler (car rest))
 747		(set! rest (cdr rest)) ]
 748	       [(-cxx)
 749		(check s rest)
 750		(set! c++-compiler (car rest))
 751		(set! rest (cdr rest)) ]
 752	       [(-ld)
 753		(check s rest)
 754		(set! linker (car rest))
 755		(set! rest (cdr rest)) ]
 756	       [(|-I|)
 757		(check s rest)
 758		(set! rest (cons* "-include-path" (car rest) (cdr rest))) ]
 759	       [(|-C|)
 760		(check s rest)
 761		(set! compile-options (append compile-options (string-split (car rest))))
 762		(set! rest (cdr rest)) ]
 763	       [(-strip)
 764		(set! link-options (append link-options (list "-s")))]
 765	       [(|-L|)
 766		(check s rest)
 767		(set! link-options (append link-options (string-split (car rest))))
 768		(set! rest (cdr rest)) ]
 769	       [(-rpath)
 770		(check s rest)
 771		(set! rpath (car rest))
 772		(when (and (memq (build-platform) '(gnu clang))
 773			   (not mingw) (not osx))
 774		  (set! link-options
 775                    (append link-options (list (string-append "-Wl," rpath-option rpath)))) )
 776	  	(set! rest (cdr rest)) ]
 777	       [(-host) #f]
 778	       ((-oi)
 779		(check s rest)
 780		(t-options "-emit-inline-file" (car rest))
 781		(set! rest (cdr rest)))
 782	       ((-ot)
 783		(check s rest)
 784		(t-options "-emit-types-file" (car rest))
 785		(set! rest (cdr rest)))
 786	       [(-)
 787		(set! scheme-files (append scheme-files '("-")))
 788		(unless target-filename
 789		  (set! target-filename (make-pathname #f "a" executable-extension)))]
 790	       [else
 791		(when (eq? s '-to-stdout)
 792		  (set! to-stdout #t)
 793		  (set! translate-only #t) )
 794		(when (memq s '(-optimize-level -benchmark-mode))
 795		  (set! compilation-optimization-options best-compilation-optimization-options)
 796		  (set! linking-optimization-options best-linking-optimization-options) )
 797		(cond [(assq s shortcuts) => (lambda (a) (set! rest (cons (cadr a) rest)))]
 798		      [(memq s simple-options) (t-options arg)]
 799		      ((memq s complex-options)
 800		       (check s rest)
 801		       (t-options arg (car rest))
 802		       (set! rest (cdr rest)))
 803		      [(and (> (string-length arg) 2) (string=? "-:" (substring arg 0 2)))
 804		       (t-options arg) ]
 805		      [(and (> (string-length arg) 1)
 806			    (char=? #\- (string-ref arg 0)) )
 807		       (cond [(char=? #\L (string-ref arg 1))
 808			      (when (char-whitespace? (string-ref arg 2))
 809				    (error "bad -L argument, <DIR> starts with whitespace" arg))
 810 			      (set! link-options (append link-options (list arg))) ]
 811 			     [(char=? #\I (string-ref arg 1))
 812			      (when (char-whitespace? (string-ref arg 2))
 813				    (error "bad -I argument: <DIR> starts with whitespace" arg))
 814 			      (set! compile-options (append compile-options (list arg))) ]
 815			     [(char=? #\D (string-ref arg 1))
 816			      (t-options "-feature" (substring arg 2)) ]
 817			     [(char=? #\F (string-ref arg 1))
 818			      (when osx
 819				(set! compile-options (append compile-options (list arg))) ) ]
 820			     [(and (> (string-length arg) 3) (string=? "-Wl," (substring arg 0 4)))
 821			      (set! link-options (append link-options (list arg))) ]
 822			     [(> (string-length arg) 2)
 823			      (let ([opts (cdr (string->list arg))])
 824				(cond ((null? (lset-difference/eq? opts short-options))
 825				       (set! rest
 826					 (append (map (lambda (o)
 827							(string-append "-" (string o))) opts)
 828						 rest) ))
 829				      ((char=? #\l (car opts))
 830				       (stop "invalid option `~A' - did you mean `-L -l<library>'?" arg))
 831				      (else (stop "invalid option `~A'" arg) ) )) ]
 832			     [else (stop "invalid option `~A'" s)] ) ]
 833		      [(file-exists? arg)
 834		       (let-values ([(dirs name ext) (decompose-pathname arg)])
 835			 (cond [(not ext)
 836				(set! scheme-files (append scheme-files (list arg)))]
 837			       [(member ext '("h" "c"))
 838				(set! c-files (append c-files (list arg))) ]
 839			       ((string-ci=? ext "rc")
 840				(set! rc-files (append rc-files (list arg))) )
 841			       [(member ext '("cpp" "C" "cc" "cxx" "hpp"))
 842				(when osx (set! compile-options (cons "-no-cpp-precomp" compile-options)))
 843				(set! cpp-mode #t)
 844				(set! c-files (append c-files (list arg))) ]
 845			       [(member ext '("m" "M" "mm"))
 846				(set! objc-mode #t)
 847				(set! c-files (append c-files (list arg))) ]
 848			       [(or (string=? ext object-extension)
 849				    (string=? ext library-extension) )
 850				(set! object-files (append object-files (list arg))) ]
 851			       [else (set! scheme-files (append scheme-files (list arg)))] ) ) ]
 852		      [else
 853		       (let ([f2 (string-append arg ".scm")])
 854			 (if (file-exists? f2)
 855			     (set! rest (cons f2 rest))
 856			     (stop "file `~A' does not exist" arg) ) ) ] ) ] )
 857	     (loop rest) ) ] ) ) )
 858
 859
 860;;; Translate all Scheme files:
 861
 862(define (run-translation)
 863  (for-each
 864   (lambda (f)
 865     (let* ((sf (if (= 1 (length scheme-files))
 866		    target-filename
 867		    f))
 868	    (fc (pathname-replace-extension
 869		 sf
 870		 (cond (cpp-mode "cpp")
 871		       (objc-mode "m")
 872		       (else "c") ) ) ) )
 873       (when (member fc c-files)
 874	 (stop "C file generated from `~a' will overwrite explicitly given source file `~a'"
 875	       f fc))
 876       (exec
 877        translator
 878	(cons* f
 879	       (append
 880		(if to-stdout
 881		    '("-to-stdout")
 882		    `("-output-file" ,fc) )
 883		(if (##sys#debug-mode?)
 884		    '("-:d")
 885		    '())
 886		extra-features
 887		translate-options
 888                (if (and static
 889                         (not (member "-emit-link-file"
 890                                      translate-options)))
 891                    (list "-emit-link-file"
 892                          (pathname-replace-extension fc "link"))
 893                    '())
 894		(cond (cpp-mode '("-feature" "chicken-scheme-to-c++"))
 895		      (objc-mode '("-feature" "chicken-scheme-to-objc"))
 896		      (else '()))
 897		translation-optimization-options ) ) )
 898       (when (and static compile-only)
 899         (set! transient-link-files
 900           (cons (pathname-replace-extension f "link")
 901                 transient-link-files)))
 902       (set! c-files (append (list fc) c-files))
 903       (set! generated-c-files (append (list fc) generated-c-files))))
 904   scheme-files))
 905
 906
 907;;; Compile all C/C++  and .rc files:
 908
 909(define (run-compilation)
 910  (let ((ofiles '()))
 911    (for-each
 912     (lambda (f)
 913       (let ((fo (if (and compile-only
 914                          target-filename
 915                          (= 1 (length c-files)))
 916                     target-filename
 917                     (pathname-replace-extension f object-extension))))
 918	 (when (member fo object-files)
 919	   (stop "object file generated from `~a' will overwrite explicitly given object file `~a'"
 920		 f fo))
 921	 (exec (cond (cpp-mode c++-compiler)
 922		     (else compiler) )
 923	       (cons* f
 924                      compile-output-flag fo
 925	              compile-only-flag
 926                      (append (if (and cpp-mode (string=? "g++" c++-compiler)) ; XXX This is somewhat hacky - g++ might not be *named* g++
 927	                          '("-Wno-write-strings")
 928	                          '())
 929	                      (compiler-options)) )  )
 930	 (set! generated-object-files (cons fo generated-object-files))
 931	 (set! ofiles (cons fo ofiles))))
 932     c-files)
 933    (when (and generate-manifest (eq? 'windows (software-type)))
 934      (let ((rcf (pathname-replace-extension target-filename "rc")))
 935	(create-win-manifest (pathname-file target-filename) rcf)
 936	(set! rc-files (cons rcf rc-files))
 937	(set! generated-rc-files (cons rcf generated-rc-files))))
 938    (for-each
 939     (lambda (f)
 940       (let ((fo (string-append f "." object-extension)))
 941	 (exec rc-compiler (list f fo))
 942	 (set! generated-object-files (cons fo generated-object-files))
 943	 (set! ofiles (cons fo ofiles))))
 944     rc-files)
 945    (set! object-files (append (reverse ofiles) object-files)) ; put generated object files first
 946    (unless keep-files
 947      (for-each $delete-file generated-c-files)
 948      (for-each $delete-file generated-rc-files))))
 949
 950(define (compiler-options)
 951  (append
 952   compilation-optimization-options
 953   compile-options) )
 954
 955
 956;;; Link object files and libraries:
 957
 958(define (run-linking)
 959  (set! object-files
 960    (collect-linked-objects object-files generated-object-files))
 961  (exec (cond (cpp-mode c++-linker)
 962	      (else linker) )
 963        (append
 964         object-files
 965         (list link-output-flag target-filename)
 966	 (linker-options)
 967	 (linker-libraries)  )   )
 968  (when (and osx host-mode)
 969    (let ((lib (string-append (libchicken) ".dylib")))
 970      (exec POSTINSTALL_PROGRAM
 971            (list "-change" lib
 972                  (if deployed
 973	              (make-pathname "@executable_path" lib)
 974	              (make-pathname (or rpath
 975                                         (if host-mode
 976                                             host-libdir
 977                                             TARGET_RUN_LIB_HOME))
 978                                     lib))
 979                  target-filename))))
 980  (unless keep-files
 981    (for-each $delete-file
 982              (append generated-object-files
 983                      transient-link-files))))
 984
 985(define (collect-linked-objects ofiles gen-ofiles)
 986  (define (locate-link-file o)
 987    (let* ((p (pathname-strip-extension o))
 988	   ;; Also strip "static.o" extension when in setup mode:
 989	   (f (if ##sys#setup-mode (string-chomp p ".static") p)))
 990      (file-exists? (make-pathname #f f "link"))))
 991  (define (locate-objects libs)
 992    (map (lambda (id)
 993	   (or (find-object-file id)
 994	       (stop "could not find linked extension: ~A" id)))
 995	 (map ->string libs)))
 996  (let loop ((os ofiles) (os2 ofiles))
 997    (cond ((null? os)
 998           (delete-duplicates (reverse os2) string=?))
 999          ((or static (not (member (car os) gen-ofiles)))
 1000           (let* ((lfile (locate-link-file (car os)))
1001                  (newos (if lfile
1002                             (locate-objects (with-input-from-file lfile read))
1003                             '())))
1004             (loop (append newos (cdr os)) (append newos os2))))
1005          (else (loop (cdr os) (cons (car os) os2))))))
1006
1007(define (copy-files from to)
1008  (exec (if windows-shell "copy" "cp")
1009        (append (if windows-shell '("/Y") '())
1010                (list from to))))
1011
1012(define (linker-options)
1013  (append linking-optimization-options link-options) )
1014
1015(define (linker-libraries)
1016  (append
1017   (if static
1018       (library-files)
1019       (shared-library-files))
1020   (if static
1021       extra-libraries
1022       extra-shared-libraries)))
1023
1024
1025;;; Helper procedures:
1026
1027;; Simpler replacement for SRFI-13's string-any
1028(define (string-any criteria s)
1029  (let ((end (string-length s)))
1030    (let lp ((i 0))
1031      (let ((c (string-ref s i))
1032            (i1 (+ i 1)))
1033        (if (= i1 end) (criteria c)
1034            (or (criteria c)
1035                (lp i1)))))))
1036
1037(define (exec prog args)
1038  ;; NOTE: We construct a command line for debugging purposes, but it
1039  ;; does not 100% represent what gets executed.
1040  (let ((cmdline (string-intersperse (map quotewrap (cons prog args)) " ")))
1041    (when verbose
1042      (print cmdline))
1043    (unless dry-run
1044      (let*-values (((pid) (process-run prog args))
1045                    ((pid success? exit-code) (process-wait pid)))
1046        (when (or (not success?) (not (zero? exit-code)))
1047          (printf "\nError: shell command terminated with non-zero exit status ~S: ~A~%" exit-code cmdline)
1048          (exit exit-code))))))
1049
1050(define ($delete-file str)
1051  (when verbose
1052    (print "rm " str) )
1053  (unless dry-run (delete-file str) ))
1054
1055(define (create-win-manifest prg rcfname)
1056  (when verbose (print "generating " rcfname))
1057  (with-output-to-file rcfname
1058    (lambda ()
1059      (print #<#EOF
10601 24 MOVEABLE PURE
1061BEGIN
1062  "<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>\r\n"
1063  "<assembly xmlns=""urn:schemas-microsoft-com:asm.v1"" manifestVersion=""1.0"">\r\n"
1064  "  <assemblyIdentity version=""1.0.0.0"" processorArchitecture=""*"" name=""#{prg}"" type=""win32""/>\r\n"
1065  "  <ms_asmv2:trustInfo xmlns:ms_asmv2=""urn:schemas-microsoft-com:asm.v2"">\r\n"
1066  "    <ms_asmv2:security>\r\n"
1067  "      <ms_asmv2:requestedPrivileges>\r\n"
1068  "        <ms_asmv2:requestedExecutionLevel level=""asInvoker"" uiAccess=""false""/>\r\n"
1069  "      </ms_asmv2:requestedPrivileges>\r\n"
1070  "    </ms_asmv2:security>\r\n"
1071  "  </ms_asmv2:trustInfo>\r\n"
1072  "</assembly>\r\n"
1073END
1074EOF
1075) ) ) )
1076
1077
1078;;; Run it:
1079
1080(run
1081 (append
1082  (string-split (or (get-environment-variable "CSC_OPTIONS") ""))
1083  arguments))
1084
1085)
Trap