"Fossies" - the Fresh Open Source Software Archive

Member "FreeBASIC-1.07.1-source/src/compiler/fbc.bas" (27 Sep 2019, 102007 Bytes) of package /linux/privat/FreeBASIC-1.07.1-source.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Visual Basic source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "fbc.bas": 1.07.0_vs_1.07.1.

    1 '' main module, front-end
    2 ''
    3 '' chng: sep/2004 written [v1ctor]
    4 ''       dec/2004 linux support added [lillo]
    5 ''       jan/2005 dos support added [DrV]
    6 
    7 #include once "fb.bi"
    8 #include once "hlp.bi"
    9 #include once "hash.bi"
   10 #include once "list.bi"
   11 #include once "objinfo.bi"
   12 
   13 #include once "file.bi"
   14 
   15 #if defined( ENABLE_STANDALONE ) and defined( __FB_WIN32__ )
   16     #define ENABLE_GORC
   17 #endif
   18 
   19 enum
   20     PRINT_HOST
   21     PRINT_TARGET
   22     PRINT_X
   23     PRINT_FBLIBDIR
   24     PRINT_SHA1
   25 end enum
   26 
   27 type FBC_EXTOPT
   28     gas         as zstring * 128
   29     ld          as zstring * 128
   30     gcc         as zstring * 128
   31 end type
   32 
   33 type FBCIOFILE
   34     '' Input file name (usually *.bas, but also *.rc, *.res, *.xpm)
   35     srcfile         as string     '' input file
   36 
   37     '' Output .o file
   38     '' - for modules from the command line this points to a node from
   39     ''   fbc.objlist, see also fbcAddObj()
   40     '' - for example in hCompileFbctinf(), add temporary FBCIOFILE is used,
   41     ''   with objfile pointing to a string var on stack
   42     objfile         as string ptr
   43 
   44     '' Whether -o was used to override the default .o file name
   45     is_custom_objfile   as integer
   46 end type
   47 
   48 type FBC_OBJINF
   49     lang        as FB_LANG
   50     mt          as integer
   51 end type
   52 
   53 type FBCCTX
   54     '' For command line parsing
   55     optid               as integer    '' Current option
   56     lastmodule          as FBCIOFILE ptr '' module for last input file, so the default .o name can be overwritten with a following -o filename
   57     objfile             as string '' -o filename waiting for next input file
   58     backend             as integer  '' FB_BACKEND_* given via -gen, or -1 if -gen wasn't given
   59     cputype             as integer  '' FB_CPUTYPE_* (-arch's argument), or -1
   60     cputype_is_native       as integer  '' Whether -arch native was used
   61     asmsyntax           as integer  '' FB_ASMSYNTAX_* from -asm, or -1 if not given
   62 
   63     emitasmonly         as integer  '' write out FB backend output file only (.asm/.c)
   64     keepasm             as integer  '' preserve FB backend output file (.asm/.c)
   65     emitfinalasmonly        as integer  '' write out final .asm file only
   66     keepfinalasm            as integer  '' preserve final .asm
   67     keepobj             as integer
   68     verbose             as integer
   69     showversion         as integer
   70     showhelp            as integer
   71     print               as integer  '' PRINT_* (-print option)
   72 
   73     '' Command line input
   74     modules             as TLIST '' FBCIOFILE's for input .bas files
   75     rcs             as TLIST '' FBCIOFILE's for input .rc/.res files
   76     xpm             as FBCIOFILE '' .xpm input file
   77     temps               as TLIST '' Temporary files to delete at shutdown
   78     objlist             as TLIST '' Objects from command line and from compilation
   79     libfiles            as TLIST
   80     libs                as TSTRSET
   81     libpaths            as TSTRSET
   82 
   83     '' Final list of libs and paths for linking
   84     '' (each module can have #inclibs and #libpaths and add more, and for
   85     '' objinfo emitting only the module-specific libs are wanted, so there
   86     '' are multiple lists necessary to allow each module to start fresh
   87     '' with the same input libs)
   88     finallibs           as TSTRSET
   89     finallibpaths           as TSTRSET
   90 
   91     outname             as zstring * FB_MAXPATHLEN+1
   92     mainname            as zstring * FB_MAXPATHLEN+1
   93     mainset             as integer
   94     mapfile             as zstring * FB_MAXPATHLEN+1
   95     subsystem           as zstring * FB_MAXNAMELEN+1
   96     extopt              as FBC_EXTOPT
   97 #ifndef ENABLE_STANDALONE
   98     target              as zstring * FB_MAXNAMELEN+1  '' Target system identifier (e.g. a name like "win32", or a GNU triplet) to prefix in front of cross-compiling tool names
   99     targetprefix            as zstring * FB_MAXNAMELEN+1  '' same, but with "-" appended, if there was a target id given; otherwise empty.
  100 #endif
  101     xbe_title           as zstring * FB_MAXNAMELEN+1  '' For the '-title <title>' xbox option
  102     nodeflibs           as integer
  103     staticlink          as integer
  104     stripsymbols            as integer
  105 
  106     '' Compiler paths
  107     prefix              as zstring * FB_MAXPATHLEN+1  '' Path from -prefix or empty
  108     binpath             as zstring * FB_MAXPATHLEN+1
  109     incpath             as zstring * FB_MAXPATHLEN+1
  110     libpath             as zstring * FB_MAXPATHLEN+1
  111 
  112     objinf              as FBC_OBJINF
  113 end type
  114 
  115 enum
  116     FBCTOOL_AS = 0
  117     FBCTOOL_AR
  118     FBCTOOL_LD
  119     FBCTOOL_GCC
  120     FBCTOOL_LLC
  121     FBCTOOL_DLLTOOL
  122     FBCTOOL_GORC
  123     FBCTOOL_WINDRES
  124     FBCTOOL_CXBE
  125     FBCTOOL_DXEGEN
  126     FBCTOOL__COUNT
  127 end enum
  128 
  129 static shared as zstring * 8 toolnames(0 to FBCTOOL__COUNT-1) = _
  130 { _
  131     "as", "ar", "ld", "gcc", "llc", "dlltool", "GoRC", "windres", "cxbe", "dxe3gen" _
  132 }
  133 
  134 declare sub fbcFindBin _
  135     ( _
  136         byval tool as integer, _
  137         byref path as string, _
  138         byref relying_on_system as integer = FALSE _
  139     )
  140 
  141 #macro safeKill(f)
  142     if( kill( f ) <> 0 ) then
  143     end if
  144 #endmacro
  145 
  146 dim shared as FBCCTX fbc
  147 
  148 private sub fbcInit( )
  149     const FBC_INITFILES = 64
  150 
  151     fbc.backend = -1
  152     fbc.cputype = -1
  153     fbc.asmsyntax = -1
  154 
  155     listInit( @fbc.modules, FBC_INITFILES, sizeof(FBCIOFILE) )
  156     listInit( @fbc.rcs, FBC_INITFILES\4, sizeof(FBCIOFILE) )
  157     strlistInit( @fbc.temps, FBC_INITFILES\4 )
  158     strlistInit( @fbc.objlist, FBC_INITFILES )
  159     strlistInit( @fbc.libfiles, FBC_INITFILES\4 )
  160     strsetInit( @fbc.libs, FBC_INITFILES\4 )
  161     strsetInit( @fbc.libpaths, FBC_INITFILES\4 )
  162 
  163     strsetInit(@fbc.finallibs, FBC_INITFILES\2)
  164     strsetInit(@fbc.finallibpaths, FBC_INITFILES\2)
  165 
  166     fbGlobalInit()
  167 
  168 #ifdef ENABLE_STRIPALL
  169     fbc.stripsymbols = TRUE
  170 #endif
  171 
  172     fbc.objinf.lang = fbGetOption( FB_COMPOPT_LANG )
  173 
  174     fbc.print = -1
  175 end sub
  176 
  177 private sub hSetOutName( )
  178     '' Determine the output binary/archive's name if not given via -x
  179     if( len( fbc.outname ) > 0 ) then
  180         exit sub
  181     end if
  182 
  183     '' Creating a static lib?
  184     if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_STATICLIB ) then
  185         fbc.outname = hStripFilename( fbc.mainname ) + _
  186                       "lib" + hStripPath( fbc.mainname ) + ".a"
  187         exit sub
  188     end if
  189 
  190     '' Otherwise, we're creating an .exe or DLL/shared lib
  191     fbc.outname = fbc.mainname
  192 
  193     select case( fbGetOption( FB_COMPOPT_OUTTYPE ) )
  194     case FB_OUTTYPE_EXECUTABLE
  195         select case( fbGetOption( FB_COMPOPT_TARGET ) )
  196         case FB_COMPTARGET_DOS, FB_COMPTARGET_CYGWIN, _
  197              FB_COMPTARGET_WIN32, FB_COMPTARGET_XBOX
  198             '' Note: XBox target creates an .exe first,
  199             '' then uses cxbe to turn it into an .xbe later
  200             fbc.outname += ".exe"
  201         end select
  202     case FB_OUTTYPE_DYNAMICLIB
  203         select case( fbGetOption( FB_COMPOPT_TARGET ) )
  204         case FB_COMPTARGET_CYGWIN, FB_COMPTARGET_WIN32
  205             fbc.outname += ".dll"
  206         case FB_COMPTARGET_LINUX, FB_COMPTARGET_DARWIN, _
  207              FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _
  208              FB_COMPTARGET_NETBSD
  209             fbc.outname = hStripFilename( fbc.outname ) + _
  210                 "lib" + hStripPath( fbc.outname ) + ".so"
  211         case FB_COMPTARGET_DOS
  212             fbc.outname += ".dxe"
  213         end select
  214     end select
  215 end sub
  216 
  217 private sub fbcEnd( byval errnum as integer )
  218     '' Clean up temporary files
  219     dim as string ptr file = listGetHead( @fbc.temps )
  220     while( file )
  221         safeKill( *file )
  222         file = listGetNext( file )
  223     wend
  224 
  225     end errnum
  226 end sub
  227 
  228 private sub fbcAddTemp(byref file as string)
  229     strlistAppend(@fbc.temps, file)
  230 end sub
  231 
  232 private function fbcAddObj( byref file as string ) as string ptr
  233     '' .o's should be linked/archived in the order they were found on
  234     '' command line, so callers of this function must take care to preserve
  235     '' the order...
  236     dim as string ptr s = listNewNode( @fbc.objlist )
  237     *s = file
  238     function = s
  239 end function
  240 
  241 private function hGet1stOutputLineFromCommand( byref cmd as string ) as string
  242     var f = freefile( )
  243     if( open pipe( cmd, for input, as f ) <> 0 ) then
  244         exit function
  245     end if
  246 
  247     dim ln as string
  248     input #f, ln
  249 
  250     close f
  251     return ln
  252 end function
  253 
  254 ''
  255 '' Build the path to a certain file in our lib/ directory (or, in case of
  256 '' non-standalone, somewhere in a system directory such as /usr/lib).
  257 ''
  258 '' standalone: Will always return the path to lib/<target>/<file>, no matter
  259 ''             whether it exists or not - because that's where it should be.
  260 ''             This way the "file not found" errors will be prettier.
  261 ''
  262 '' normal: Will check lib/ and query gcc if not found. Querying gcc may fail,
  263 ''         because of that an empty string may be returned.
  264 ''
  265 private function fbcBuildPathToLibFile( byval file as zstring ptr ) as string
  266     dim as string found
  267 
  268     ''
  269     '' The Standalone build expects to have all needed files in its lib/,
  270     '' so it needs to do nothing but build up the path and use that.
  271     ''
  272     '' Normal however wants to use the "system's" files (and only has few
  273     '' files in its own lib/).
  274     ''
  275     '' Typically libgcc.a, crtbegin.o, crtend.o will be inside
  276     '' gcc's sub-directory in lib/gcc/target/version, i.e. Normal can only
  277     '' find them via 'gcc -print-file-name=foo' (except for hard-coding
  278     '' against a specific gcc target/version, but that's not a good option).
  279     ''
  280 
  281     found = fbc.libpath + FB_HOST_PATHDIV + *file
  282 
  283 #ifndef ENABLE_STANDALONE
  284     '' Does it exist in our lib/?
  285     if( hFileExists( found ) ) then
  286         '' Overrides anything else
  287         return found
  288     end if
  289 
  290     '' Not found in our lib/, query the target-specific gcc
  291     dim as string path
  292     fbcFindBin( FBCTOOL_GCC, path )
  293 
  294     select case( fbGetCpuFamily( ) )
  295     case FB_CPUFAMILY_X86
  296         path += " -m32"
  297     case FB_CPUFAMILY_X86_64
  298         path += " -m64"
  299     end select
  300 
  301     path += " -print-file-name=" + *file
  302 
  303     found = hGet1stOutputLineFromCommand( path )
  304     if( len( found ) = 0 ) then
  305         exit function
  306     end if
  307 
  308     if( found = hStripPath( found ) ) then
  309         exit function
  310     end if
  311 #endif
  312 
  313     function = found
  314 end function
  315 
  316 '' Retrieve the path to a library file, or an empty string if it can't be found.
  317 private function fbcFindLibFile( byval file as zstring ptr ) as string
  318     dim as string found
  319     found = fbcBuildPathToLibFile( file )
  320     if( len( found ) > 0 ) then
  321         if( hFileExists( found ) = FALSE ) then
  322             found = ""
  323         end if
  324     end if
  325     function = found
  326 end function
  327 
  328 private sub fbcAddDefLibPath(byref path as string)
  329     strsetAdd(@fbc.finallibpaths, path, TRUE)
  330 end sub
  331 
  332 #ifndef ENABLE_STANDALONE
  333 private sub fbcAddLibPathFor( byval libname as zstring ptr )
  334     dim as string path
  335     path = hStripFilename( fbcBuildPathToLibFile( libname ) )
  336     path = pathStripDiv( path )
  337     if( len( path ) > 0 ) then
  338         fbcAddDefLibPath( path )
  339     end if
  340 end sub
  341 #endif
  342 
  343 private sub fbcFindBin _
  344     ( _
  345         byval tool as integer, _
  346         byref path as string, _
  347         byref relying_on_system as integer _
  348     )
  349 
  350     static as integer lasttool = -1, last_relying_on_system
  351     static as string lastpath
  352 
  353     '' Re-use path from last time if possible
  354     if( lasttool = tool ) then
  355         path = lastpath
  356         relying_on_system = last_relying_on_system
  357         exit sub
  358     end if
  359 
  360     relying_on_system = FALSE
  361 
  362     '' a) Use the path from the corresponding environment variable if it's set
  363     path = environ( ucase( toolnames(tool) ) )
  364     if( len( path ) = 0 ) then
  365         '' b) Try bin/ directory
  366         path = fbc.binpath + toolnames(tool) + FB_HOST_EXEEXT
  367 
  368         #ifndef ENABLE_STANDALONE
  369             if( hFileExists( path ) = FALSE ) then
  370                 '' c) Rely on PATH
  371                 path = fbc.targetprefix + toolnames(tool) + FB_HOST_EXEEXT
  372                 relying_on_system = TRUE
  373             end if
  374         #endif
  375     end if
  376 
  377     lasttool = tool
  378     lastpath = path
  379     last_relying_on_system = relying_on_system
  380 end sub
  381 
  382 private function fbcRunBin _
  383     ( _
  384         byval action as zstring ptr, _
  385         byval tool as integer, _
  386         byref ln as string _
  387     ) as integer
  388 
  389     dim as integer result = any, relying_on_system = any
  390     dim as string path
  391 
  392     fbcFindBin( tool, path, relying_on_system )
  393 
  394     if( fbc.verbose ) then
  395         print *action + ": ", path + " " + ln
  396     end if
  397 
  398     '' Always use exec() on Unix or for standalone because
  399     '' - Unix exec() already searches the PATH, so shell() isn't needed,
  400     '' - standalone doesn't use system-wide tools
  401     #if defined( __FB_UNIX__ ) or defined( ENABLE_STANDALONE )
  402         result = exec( path, ln )
  403     #else
  404         '' Found at bin/?
  405         if( relying_on_system = FALSE ) then
  406             result = exec( path, ln )
  407         else
  408             result = shell( path + " " + ln )
  409         end if
  410     #endif
  411 
  412     if( result = 0 ) then
  413         function = TRUE
  414     elseif( result < 0 ) then
  415         errReportEx( FB_ERRMSG_EXEMISSING, path, -1, FB_ERRMSGOPT_ADDCOLON or FB_ERRMSGOPT_ADDQUOTES )
  416     else
  417         '' Report bad exit codes only in verbose mode; normally the
  418         '' program should already have shown an error message, and the
  419         '' exit code is only interesting for debugging purposes.
  420         if( fbc.verbose ) then
  421             print *action + " failed: '" + path + "' terminated with exit code " + str( result )
  422         end if
  423     end if
  424 end function
  425 
  426 #if defined( __FB_WIN32__ ) or defined( __FB_DOS__ )
  427 private function hPutLdArgsIntoFile( byref ldcline as string ) as integer
  428     dim as string argsfile, ln
  429     dim as integer f = any
  430 
  431     argsfile = hStripFilename( fbc.outname ) + "ldopt.tmp"
  432 
  433     f = freefile( )
  434     if( open( argsfile, for output, as #f ) ) then
  435         exit function
  436     end if
  437 
  438     ''
  439     '' MinGW ld (including the MinGW-to-DJGPP cross-compiling ld) treats \
  440     '' backslashes in @files (response files) as escape sequence, so \ must
  441     '' be escaped as \\. ld seems to behave pretty much like Unixish shells
  442     '' would: all \'s indicate an escape sequence. (For reference,
  443     '' binutils/libiberty source code: expandargv(), buildargv())
  444     ''
  445     '' With DJGPP ld however, \ chars do not seem to indicate escape
  446     '' sequences, despite the DJGPP FAQ (http://www.delorie.com/djgpp/v2faq/faq16_3.html)
  447     '' which says that \ is special in some cases such as \" or \\.
  448     '' Thus we mustn't (and don't need to) use \\ when using DJGPP ld.
  449     ''
  450     ln = ldcline
  451     #ifdef __FB_WIN32__
  452         ln = hReplace( ln, $"\", $"\\" )
  453     #endif
  454 
  455     print #f, ln
  456 
  457     close #f
  458 
  459     '' Clean up the @file if -R wasn't given
  460     if( fbc.keepasm = FALSE ) then
  461         fbcAddTemp( argsfile )
  462     end if
  463 
  464     if( fbc.verbose ) then
  465         print "ld options in '" & argsfile & "': ", ldcline
  466     end if
  467 
  468     ldcline = "@" + argsfile
  469     function = TRUE
  470 end function
  471 #endif
  472 
  473 private function clearDefList(byref deffile as string) as integer
  474     dim as integer fi = freefile()
  475     if (open(deffile, for input, as #fi)) then
  476         return FALSE
  477     end if
  478 
  479     dim as string cleaned = hStripExt(deffile) + ".clean.def"
  480     dim as integer fo = freefile()
  481     if (open(cleaned, for output, as #fo)) then
  482         close #fi
  483         return FALSE
  484     end if
  485 
  486     dim as string ln
  487     while (eof(fi) = FALSE)
  488         line input #fi, ln
  489 
  490         if (right(ln, 4) = "DATA") then
  491             ln = left(ln, len(ln) - 4)
  492         end if
  493 
  494         print #fo, ln
  495     wend
  496 
  497     close #fo
  498     close #fi
  499 
  500     kill(deffile)
  501     return (name(cleaned, deffile) = 0)
  502 end function
  503 
  504 private function hGenerateEmptyDefFile( byref deffile as string ) as integer
  505     var f = freefile( )
  506     if( open( deffile, for output, as #f ) ) then
  507         exit function
  508     end if
  509 
  510     print #f, "EXPORTS"
  511 
  512     close #f
  513     function = TRUE
  514 end function
  515 
  516 private function makeImpLib _
  517     ( _
  518         byref dllname as string, _
  519         byref deffile as string _
  520     ) as integer
  521 
  522     '' for some weird reason, LD will declare all functions exported as if they were
  523     '' from DATA segment, causing an exception (UPPERCASE'd symbols assumption??)
  524     if( clearDefList( deffile ) = FALSE ) then
  525         exit function
  526     end if
  527 
  528     '' If the .def file is empty (happens if there were no EXPORTs),
  529     '' then add a single "EXPORTS" line, otherwise dlltool will complain
  530     '' about a syntax error. (ld --output-def should probably do this
  531     '' automatically, or dlltool should be fixed, but oh well)
  532     if( filelen( deffile ) = 0 ) then
  533         if( hGenerateEmptyDefFile( deffile ) = FALSE ) then
  534             exit function
  535         end if
  536     end if
  537 
  538     dim as string ln
  539     ln += "--def """ + deffile + """"
  540     ln += " --dllname """ + hStripPath( fbc.outname ) + """"
  541     ln += " --output-lib """ + hStripFilename( fbc.outname ) + "lib" + dllname + ".dll.a"""
  542 
  543     if( fbcRunBin( "creating import library", FBCTOOL_DLLTOOL, ln ) = FALSE ) then
  544         exit function
  545     end if
  546 
  547     '' Clean up the .def file if -R wasn't given
  548     if( fbc.keepasm = FALSE ) then
  549         fbcAddTemp( deffile )
  550     end if
  551 
  552     function = TRUE
  553 end function
  554 
  555 '' Find a library file and wrap it into ""'s for passing it on the ld command
  556 '' line. Or if it couldn't be found, show an error.
  557 private function hFindLib( byval file as zstring ptr ) as string
  558     dim as string found = fbcBuildPathToLibFile( file )
  559     if( len( found ) > 0 ) then
  560         function = " """ + found + """"
  561     else
  562         errReportEx( FB_ERRMSG_FILENOTFOUND, file, -1 )
  563     end if
  564 end function
  565 
  566 private function fbcLinkerIsGold( ) as integer
  567     dim ldcmd as string
  568     fbcFindBin( FBCTOOL_LD, ldcmd )
  569     ldcmd += " --version"
  570     return (instr( hGet1stOutputLineFromCommand( ldcmd ), "GNU gold" ) > 0)
  571 end function
  572 
  573 '' Check whether we're using the gold linker.
  574 private function fbcIsUsingGoldLinker( ) as integer
  575     '' gold only supports ELF, we only need to check for it when targetting ELF.
  576     if( fbTargetSupportsELF( ) ) then
  577         return fbcLinkerIsGold( )
  578     end if
  579     return FALSE
  580 end function
  581 
  582 private function hLinkFiles( ) as integer
  583     dim as string ldcline, dllname, deffile
  584 
  585     function = FALSE
  586 
  587     hSetOutName( )
  588 
  589     select case( fbGetOption( FB_COMPOPT_TARGET ) )
  590     case FB_COMPTARGET_WIN32
  591         select case( fbGetCpuFamily( ) )
  592         case FB_CPUFAMILY_X86
  593             ldcline += "-m i386pe "
  594         case FB_CPUFAMILY_X86_64
  595             ldcline += "-m i386pep "
  596         end select
  597     case FB_COMPTARGET_LINUX
  598         select case( fbGetCpuFamily( ) )
  599         case FB_CPUFAMILY_X86
  600             ldcline += "-m elf_i386 "
  601         case FB_CPUFAMILY_X86_64
  602             ldcline += "-m elf_x86_64 "
  603         case FB_CPUFAMILY_ARM
  604             ldcline += "-m armelf_linux_eabi "
  605         end select
  606     end select
  607 
  608     '' Set executable name
  609     ldcline += "-o " + QUOTE + fbc.outname + QUOTE
  610 
  611 #ifdef __FB_DOS__
  612     if (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS) and _
  613      (fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB) then
  614         ldcline += " -I """ + hStripExt( fbc.outname ) + "_il.a"""
  615         ldcline += " -U"
  616         scope
  617             dim as string ptr objfile = listGetHead( @fbc.objlist )
  618             while( objfile )
  619                 ldcline += " """ + *objfile + """"
  620                 objfile = listGetNext( objfile )
  621             wend
  622         end scope
  623         scope
  624             dim as string ptr libfile = listGetHead(@fbc.libfiles)
  625             if (libfile) then
  626                 ldcline +=  " -lc"
  627             end if
  628             while (libfile)
  629                 ldcline += " """ + *libfile + """"
  630                 libfile = listGetNext(libfile)
  631             wend
  632         end scope
  633         if( hPutLdArgsIntoFile( ldcline ) = FALSE ) then
  634             exit function
  635         end if
  636 
  637         function = fbcRunBin( "making DXE", FBCTOOL_DXEGEN, ldcline )
  638         exit function
  639     end if
  640 #endif
  641 
  642     select case as const fbGetOption( FB_COMPOPT_TARGET )
  643     case FB_COMPTARGET_CYGWIN, FB_COMPTARGET_WIN32
  644 
  645         '' set default subsystem mode
  646         if( len( fbc.subsystem ) = 0 ) then
  647             fbc.subsystem = "console"
  648         else
  649             if( fbc.subsystem = "gui" ) then
  650                 fbc.subsystem = "windows"
  651             end if
  652         end if
  653 
  654         ldcline += " -subsystem " + fbc.subsystem
  655 
  656         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
  657             ''
  658             dllname = hStripPath( hStripExt( fbc.outname ) )
  659 
  660             '' create a dll
  661             ldcline += " --dll --enable-stdcall-fixup"
  662 
  663             '' Specify the DLL entry-point, like gcc:
  664             '' with underscore and @N stdcall suffix on x86,
  665             '' but without that for x86_64.
  666             if( fbGetCpuFamily( ) = FB_CPUFAMILY_X86 ) then
  667                 ldcline += " -e _DllMainCRTStartup@12"
  668             else
  669                 ldcline += " -e DllMainCRTStartup"
  670             end if
  671         end if
  672 
  673     case FB_COMPTARGET_LINUX, FB_COMPTARGET_DARWIN, _
  674          FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _
  675          FB_COMPTARGET_NETBSD
  676 
  677         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
  678             dllname = hStripPath( hStripExt( fbc.outname ) )
  679             ldcline += " -shared -h" + hStripPath( fbc.outname )
  680 
  681             '' Turn libfoo into foo, so it can be checked against -l foo below
  682             if( left( dllname, 3 ) = "lib" ) then
  683                 dllname = right( dllname, len( dllname ) - 3 )
  684             end if
  685         else
  686             select case as const fbGetOption( FB_COMPOPT_TARGET )
  687             case FB_COMPTARGET_FREEBSD
  688                 ldcline += " -dynamic-linker /libexec/ld-elf.so.1"
  689             case FB_COMPTARGET_LINUX
  690                 select case( fbGetCpuFamily( ) )
  691                 case FB_CPUFAMILY_X86
  692                     ldcline += " -dynamic-linker /lib/ld-linux.so.2"
  693                 case FB_CPUFAMILY_X86_64
  694                     ldcline += " -dynamic-linker /lib64/ld-linux-x86-64.so.2"
  695                 case FB_CPUFAMILY_ARM
  696                     ldcline += " -dynamic-linker /lib/ld-linux-armhf.so.3"
  697                 case FB_CPUFAMILY_AARCH64
  698                     ldcline += " -dynamic-linker /lib/ld-linux-aarch64.so.1"
  699                 end select
  700             case FB_COMPTARGET_NETBSD
  701                 ldcline += " -dynamic-linker /usr/libexec/ld.elf_so"
  702             case FB_COMPTARGET_OPENBSD
  703                 ldcline += " -dynamic-linker /usr/libexec/ld.so"
  704             end select
  705         end if
  706 
  707         '' Add all symbols to the dynamic symbol table
  708         if( (fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB) or _
  709             fbGetOption( FB_COMPOPT_EXPORT ) ) then
  710             ldcline += " --export-dynamic"
  711         end if
  712 
  713     case FB_COMPTARGET_XBOX
  714         ldcline += " -nostdlib --file-alignment 0x20 --section-alignment 0x20 -shared"
  715 
  716     end select
  717 
  718     if (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS) then
  719         '' For DJGPP, the custom ldscript must always be used,
  720         '' to get ctors/dtors into the correct order that lets
  721         '' fbrt0's c/dtor be the first/last respectively.
  722         '' (needed until binutils' default DJGPP ldscripts are fixed)
  723         ldcline += " -T """ + fbc.libpath + (FB_HOST_PATHDIV + "i386go32.x""")
  724     else
  725         '' Supplementary ld script to drop the fbctinf objinfo section
  726         ''  - only if objinfo is enabled
  727         ''  - only with ld.bfd, not ld.gold, because gold doesn't support this kind
  728         ''    of linker script (results in broken binaries).
  729         if( fbGetOption( FB_COMPOPT_OBJINFO ) and _
  730             (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) and _
  731             (not fbcIsUsingGoldLinker( )) ) then
  732             ldcline += " """ + fbc.libpath + (FB_HOST_PATHDIV + "fbextra.x""")
  733         end if
  734     end if
  735 
  736     select case as const fbGetOption( FB_COMPOPT_TARGET )
  737     case FB_COMPTARGET_CYGWIN, FB_COMPTARGET_WIN32
  738         '' stack size
  739         dim as integer stacksize = fbGetOption(FB_COMPOPT_STACKSIZE)
  740         ldcline += " --stack " + str(stacksize) + "," + str(stacksize)
  741 
  742         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
  743             '' When building DLLs, we also create an import library, as
  744             '' convenience for the user. There are several ways to do this:
  745             ''    a) ld --output-def + dlltool
  746             ''    b) ld --output-def --out-implib
  747             ''    c) pexports + dlltool
  748             '' At the moment it seems like "ld --out-implib" alone
  749             '' does not work, and b) shows a verbose message that
  750             '' wouldn't be nice to have, so a) is the best way.
  751             deffile = hStripExt( fbc.outname ) + ".def"
  752             ldcline += " --output-def """ + deffile + """"
  753         end if
  754 
  755     case FB_COMPTARGET_XBOX
  756         '' set entry point
  757         ldcline += " -e _WinMainCRTStartup"
  758 
  759     end select
  760 
  761     if (fbc.staticlink) then
  762         ldcline += " -Bstatic"
  763     end if
  764 
  765     if( len( fbc.mapfile ) > 0) then
  766         ldcline += " -Map " + fbc.mapfile
  767     end if
  768 
  769     if( fbGetOption( FB_COMPOPT_DEBUGINFO ) = FALSE ) then
  770         if( fbGetOption( FB_COMPOPT_PROFILE ) = FALSE ) then
  771             if( fbc.stripsymbols ) then
  772                 ldcline += " -s"
  773             end if
  774         end if
  775     end if
  776 
  777     '' Add the library search paths
  778     scope
  779         dim as TSTRSETITEM ptr i = listGetHead(@fbc.finallibpaths.list)
  780         while (i)
  781             ldcline += " -L """ + i->s + """"
  782             i = listGetNext(i)
  783         wend
  784     end scope
  785 
  786     '' crt begin objects
  787     select case as const fbGetOption( FB_COMPOPT_TARGET )
  788     case FB_COMPTARGET_CYGWIN
  789         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
  790             ldcline += hFindLib( "crt0.o" )
  791         else
  792             '' TODO
  793             ldcline += hFindLib( "crt0.o" )
  794             '' additional support for gmon
  795             if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
  796                 ldcline += hFindLib( "gcrt0.o" )
  797             end if
  798         end if
  799 
  800     case FB_COMPTARGET_WIN32
  801         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
  802             ldcline += hFindLib( "dllcrt2.o" )
  803         else
  804             ldcline += hFindLib( "crt2.o" )
  805             '' additional support for gmon
  806             if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
  807                 ldcline += hFindLib( "gcrt2.o" )
  808             end if
  809         end if
  810 
  811         ldcline += hFindLib( "crtbegin.o" )
  812 
  813     case FB_COMPTARGET_DOS
  814         if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
  815             ldcline += hFindLib( "gcrt0.o" )
  816         else
  817             ldcline += hFindLib( "crt0.o" )
  818         end if
  819 
  820     case FB_COMPTARGET_LINUX, FB_COMPTARGET_DARWIN, _
  821          FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _
  822          FB_COMPTARGET_NETBSD
  823 
  824         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_EXECUTABLE) then
  825             if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
  826                 select case as const fbGetOption( FB_COMPOPT_TARGET )
  827                 case FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD
  828                     ldcline += hFindLib( "gcrt0.o" )
  829                 case else
  830                     ldcline += hFindLib( "gcrt1.o" )
  831                 end select
  832             else
  833                 select case as const fbGetOption( FB_COMPOPT_TARGET )
  834                 case FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD
  835                     ldcline += hFindLib( "crt0.o" )
  836                 case else
  837                     ldcline += hFindLib( "crt1.o" )
  838                 end select
  839             end if
  840         end if
  841 
  842         if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then
  843             '' All have crti.o, except OpenBSD and Darwin
  844             if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_OPENBSD) then
  845                 ldcline += hFindLib( "crti.o" )
  846             end if
  847 
  848             if( fbGetOption( FB_COMPOPT_PIC ) ) then
  849                 ldcline += hFindLib( "crtbeginS.o" )
  850             else
  851                 ldcline += hFindLib( "crtbegin.o" )
  852             end if
  853         end if
  854 
  855     case FB_COMPTARGET_XBOX
  856         '' link with crt0.o (C runtime init)
  857         ldcline += hFindLib( "crt0.o" )
  858 
  859     end select
  860 
  861     if( fbc.nodeflibs = FALSE ) then
  862         ldcline += " """ + fbc.libpath + FB_HOST_PATHDIV
  863         if( fbGetOption( FB_COMPOPT_PIC ) ) then
  864             ldcline += "fbrt0pic.o"
  865         else
  866             ldcline += "fbrt0.o"
  867         end if
  868         ldcline += """"
  869     end if
  870 
  871     scope
  872         dim as string ptr objfile = listGetHead( @fbc.objlist )
  873         while( objfile )
  874             ldcline += " """ + *objfile + """"
  875             objfile = listGetNext( objfile )
  876         wend
  877     end scope
  878 
  879     '' Begin of lib group
  880     '' All libraries are passed inside -( -) so we don't need to worry as
  881     '' much about their order and/or listing them repeatedly.
  882     if ( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN ) then
  883         ldcline += " ""-("""
  884     end if
  885 
  886     '' Add libraries passed by file name
  887     scope
  888         dim as string ptr libfile = listGetHead(@fbc.libfiles)
  889         while (libfile)
  890             ldcline += " """ + *libfile + """"
  891             libfile = listGetNext(libfile)
  892         wend
  893     end scope
  894 
  895     '' Add libraries from command-line, those found during parsing, and
  896     '' the default ones
  897     scope
  898         dim as TSTRSETITEM ptr i = listGetHead(@fbc.finallibs.list)
  899         dim as integer checkdllname = (fbGetOption(FB_COMPOPT_OUTTYPE) = FB_OUTTYPE_DYNAMICLIB)
  900         while (i)
  901             '' Prevent linking DLLs against their own import library,
  902             '' or .so's against themselves (ld will fail to read in
  903             '' its output file...)
  904             if ((checkdllname = FALSE) orelse (i->s <> dllname)) then
  905                 ldcline += " -l" + i->s
  906             end if
  907             i = listGetNext(i)
  908         wend
  909     end scope
  910 
  911     if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then
  912         '' End of lib group
  913         ldcline += " ""-)"""
  914     end if
  915 
  916     '' crt end
  917     select case as const fbGetOption( FB_COMPOPT_TARGET )
  918     case FB_COMPTARGET_LINUX, FB_COMPTARGET_FREEBSD, _
  919          FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD
  920         if( fbGetOption( FB_COMPOPT_PIC ) ) then
  921             ldcline += hFindLib( "crtendS.o" )
  922         else
  923             ldcline += hFindLib( "crtend.o" )
  924         end if
  925         if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_OPENBSD) then
  926             ldcline += hFindLib( "crtn.o" )
  927         end if
  928 
  929     case FB_COMPTARGET_WIN32
  930         ldcline += hFindLib( "crtend.o" )
  931 
  932     end select
  933 
  934     if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then
  935         ldcline += " -macosx_version_min 10.6"
  936     end if
  937 
  938     '' extra options
  939     ldcline += " " + fbc.extopt.ld
  940 
  941     '' On some systems there are certain command line length limits which we
  942     '' can easily hit with our ld invocation, especially when linking huge
  943     '' programs, with lots of *.o files with long file names, such as the
  944     '' FB test suite.
  945     '' Typically > 127 chars but < 8k, but with huge programs, even > 32k.
  946     ''
  947     '' On DOS there's a 127 char command line length limit. Our ld command
  948     '' line will typically be much longer than that, so we use ld's @file
  949     '' feature ("ld @file") and put the command line into that file.
  950     ''
  951     '' The same happens on Win32 when we're invoking DOS .exes (some people
  952     '' use DOS binutils, instead of proper Win32-to-DOS binutils, to compile
  953     '' for DOS on Win32).
  954     ''
  955     '' On Win32, there are multiple command line length limits to worry
  956     '' about:
  957     ''    - cmd.exe (applies to FB shell()): 8192 on Windows XP+,
  958     ''      2047 on Windows NT 4.0/2000
  959     ''    - 32767 for CreateProcess() (applies to FB exec())
  960     '' fbcRunBin() can use either shell() or exec() depending on whether
  961     '' it's a normal/standalone build and whether the binutils were found.
  962     '' For standalone, it will always use exec(), but for non-standalone,
  963     '' we don't know what it'll do, so we should use the minimum limit.
  964     '' For shell() the full command line will also include the ld.exe
  965     '' command, i.e. "[<target>-]ld.exe ", which reduces the amount of room
  966     '' left over for the ld arguments.
  967     ''
  968     '' On Linux/BSD systems there's typically some 100k or 200k limit which
  969     '' we usually don't hit.
  970     #ifdef __FB_DOS__
  971         if( hPutLdArgsIntoFile( ldcline ) = FALSE ) then
  972             exit function
  973         end if
  974     #elseif defined( __FB_WIN32__ )
  975         #ifdef ENABLE_STANDALONE
  976             if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS ) then
  977                 if( hPutLdArgsIntoFile( ldcline ) = FALSE ) then
  978                     exit function
  979                 end if
  980             end if
  981         #else
  982             if( (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS) or _
  983                 (len( ldcline ) > (2047 - len( "ld.exe " ) - len( fbc.targetprefix ))) ) then
  984                 if( hPutLdArgsIntoFile( ldcline ) = FALSE ) then
  985                     exit function
  986                 end if
  987             end if
  988         #endif
  989     #endif
  990 
  991     '' invoke ld
  992     if( fbcRunBin( "linking", FBCTOOL_LD, ldcline ) = FALSE ) then
  993         exit function
  994     end if
  995 
  996     select case as const fbGetOption( FB_COMPOPT_TARGET )
  997     case FB_COMPTARGET_DOS
  998         '' patch the exe to change the stack size
  999         dim as integer f = freefile()
 1000 
 1001         if (open(fbc.outname, for binary, access read write, as #f) <> 0) then
 1002             exit function
 1003         end if
 1004 
 1005         put #f, 533, clng( fbGetOption( FB_COMPOPT_STACKSIZE ) )
 1006 
 1007         close #f
 1008 
 1009     case FB_COMPTARGET_CYGWIN, FB_COMPTARGET_WIN32
 1010         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
 1011             '' Create the .dll.a import library from the generated .def
 1012             if (makeImpLib(dllname, deffile) = FALSE) then
 1013                 exit function
 1014             end if
 1015         end if
 1016 
 1017     case FB_COMPTARGET_XBOX
 1018         '' Turn .exe into .xbe
 1019         dim as string cxbepath, cxbecline
 1020         dim as integer res = any
 1021 
 1022         '' xbe title
 1023         if( len(fbc.xbe_title) = 0 ) then
 1024             fbc.xbe_title = hStripExt(fbc.outname)
 1025         end if
 1026 
 1027         cxbecline = "-TITLE:" + QUOTE + fbc.xbe_title + (QUOTE + " ")
 1028 
 1029         if( fbGetOption( FB_COMPOPT_DEBUGINFO ) ) then
 1030             cxbecline += "-DUMPINFO:" + QUOTE + hStripExt(fbc.outname) + (".cxbe" + QUOTE)
 1031         end if
 1032 
 1033         '' output xbe filename
 1034         cxbecline += " -OUT:" + QUOTE + hStripExt(fbc.outname) + ".xbe" + QUOTE
 1035 
 1036         '' input exe filename
 1037         cxbecline += " " + QUOTE + fbc.outname + QUOTE
 1038 
 1039         '' don't echo cxbe output
 1040         if( fbc.verbose = FALSE ) then
 1041             cxbecline += " >nul"
 1042         end if
 1043 
 1044         '' invoke cxbe (exe -> xbe)
 1045         if( fbc.verbose ) then
 1046             print "cxbe: ", cxbecline
 1047         end if
 1048 
 1049         fbcFindBin( FBCTOOL_CXBE, cxbepath )
 1050 
 1051         '' have to use shell instead of exec in order to use >nul
 1052         res = shell(cxbepath + " " + cxbecline)
 1053         if( res <> 0 ) then
 1054             if( fbc.verbose ) then
 1055                 print "cxbe failed: exit code " & res
 1056             end if
 1057             exit function
 1058         end if
 1059 
 1060         '' remove .exe
 1061         kill fbc.outname
 1062 
 1063     end select
 1064 
 1065     function = TRUE
 1066 
 1067 end function
 1068 
 1069 private sub hReadObjinfo( )
 1070     dim as string dat
 1071     dim as integer lang = any
 1072 
 1073     #macro hReportErr( num )
 1074         errReportWarnEx( num, objinfoGetFilename( ), -1 )
 1075     #endmacro
 1076 
 1077     do
 1078         select case as const( objinfoReadNext( dat ) )
 1079         case OBJINFO_LIB
 1080             strsetAdd( @fbc.finallibs, dat, FALSE )
 1081 
 1082         case OBJINFO_LIBPATH
 1083             strsetAdd( @fbc.finallibpaths, dat, FALSE )
 1084 
 1085         case OBJINFO_MT
 1086             if( fbc.objinf.mt = FALSE ) then
 1087                 hReportErr( FB_WARNINGMSG_MIXINGMTMODES )
 1088 
 1089                 fbc.objinf.mt = TRUE
 1090                 fbSetOption( FB_COMPOPT_MULTITHREADED, TRUE )
 1091             end if
 1092 
 1093         case OBJINFO_GFX
 1094             fbSetOption( FB_COMPOPT_GFX, TRUE )
 1095 
 1096         case OBJINFO_LANG
 1097             lang = fbGetLangId( dat )
 1098 
 1099             '' bad objinfo value?
 1100             if( lang = FB_LANG_INVALID ) then
 1101                 lang = FB_LANG_FB
 1102             end if
 1103 
 1104             if( lang <> fbc.objinf.lang ) then
 1105                 hReportErr( FB_WARNINGMSG_MIXINGLANGMODES )
 1106                 fbc.objinf.lang = lang
 1107                 fbSetOption( FB_COMPOPT_LANG, lang )
 1108             end if
 1109 
 1110         case else
 1111             exit do
 1112         end select
 1113     loop
 1114 
 1115     objinfoReadEnd( )
 1116 end sub
 1117 
 1118 private sub hCollectObjinfo( )
 1119     dim as string ptr s = any
 1120     dim as TSTRSETITEM ptr i = any
 1121 
 1122     '' for each object passed in the cmd-line
 1123     s = listGetHead( @fbc.objlist )
 1124     while( s )
 1125         objinfoReadObj( *s )
 1126         hReadObjinfo( )
 1127         s = listGetNext( s )
 1128     wend
 1129 
 1130     '' for each library found (must be done after processing all objects)
 1131     i = listGetHead( @fbc.finallibs.list )
 1132     while( i )
 1133         '' Not default?
 1134         if( i->userdata = FALSE ) then
 1135             objinfoReadLib( i->s, @fbc.finallibpaths.list )
 1136             hReadObjinfo( )
 1137         end if
 1138         i = listGetNext( i )
 1139     wend
 1140 
 1141     '' Search libs given as *.a input files instead of -l or #inclib
 1142     s = listGetHead( @fbc.libfiles )
 1143     while( s )
 1144         objinfoReadLibfile( *s )
 1145         hReadObjinfo( )
 1146         s = listGetNext( s )
 1147     wend
 1148 end sub
 1149 
 1150 private sub hFatalInvalidOption( byref arg as string )
 1151     errReportEx( FB_ERRMSG_INVALIDCMDOPTION, QUOTE + arg + QUOTE, -1 )
 1152     fbcEnd( 1 )
 1153 end sub
 1154 
 1155 private sub hCheckWaitingObjfile( )
 1156     if( len( fbc.objfile ) > 0 ) then
 1157         errReportEx( FB_ERRMSG_OBJFILEWITHOUTINPUTFILE, "-o " & fbc.objfile, -1 )
 1158         fbc.objfile = ""
 1159     end if
 1160 end sub
 1161 
 1162 private sub hSetIofile _
 1163     ( _
 1164         byval module as FBCIOFILE ptr, _
 1165         byref srcfile as string, _
 1166         byval is_rc as integer _
 1167     )
 1168 
 1169     module->srcfile = srcfile
 1170 
 1171     '' No objfile name set yet (from the -o <file> option)?
 1172     if( len( fbc.objfile ) = 0 ) then
 1173         module->is_custom_objfile = FALSE
 1174 
 1175         '' Choose default *.o name based on input file name
 1176         if( is_rc ) then
 1177 #ifdef ENABLE_GORC
 1178             '' GoRC only accepts *.obj
 1179             '' foo.rc -> foo.obj, so there is no collision with foo.bas' foo.o
 1180             fbc.objfile = hStripExt( srcfile ) + ".obj"
 1181 #else
 1182             '' windres doesn't care, so we use the default *.o
 1183             '' foo.rc -> foo.rc.o to avoid collision with foo.bas' foo.o
 1184             fbc.objfile = srcfile + ".o"
 1185 #endif
 1186         else
 1187             '' foo.bas -> foo.o
 1188             fbc.objfile = hStripExt( srcfile ) + ".o"
 1189         end if
 1190 
 1191         '' Since there was no preceding -o for this module, allow
 1192         '' -o <file> to follow later
 1193         fbc.lastmodule = module
 1194     else
 1195         module->is_custom_objfile = TRUE
 1196     end if
 1197 
 1198     module->objfile = fbcAddObj( fbc.objfile )
 1199     fbc.objfile = ""
 1200 
 1201 end sub
 1202 
 1203 private sub hAddBas( byref basfile as string )
 1204     hSetIofile( listNewNode( @fbc.modules ), basfile, FALSE )
 1205 end sub
 1206 
 1207 type FBGNUOSINFO
 1208     gnuid       as zstring ptr  '' Part of GNU triplet identifying a certain OS
 1209     os      as integer      '' Corresponding FB_COMPTARGET_*
 1210 end type
 1211 
 1212 type FBGNUARCHINFO
 1213     gnuid       as zstring ptr  '' Part of GNU triplet identifying a certain architecture
 1214     cputype     as integer      '' Corresponding FB_CPUTYPE_*
 1215 end type
 1216 
 1217 '' OS name strings recognized when parsing GNU triplets (-target option)
 1218 dim shared as FBGNUOSINFO gnuosmap(0 to ...) => _
 1219 { _
 1220     (@"linux"  , FB_COMPTARGET_LINUX  ), _
 1221     (@"mingw"  , FB_COMPTARGET_WIN32  ), _
 1222     (@"djgpp"  , FB_COMPTARGET_DOS    ), _
 1223     (@"cygwin" , FB_COMPTARGET_CYGWIN ), _
 1224     (@"darwin" , FB_COMPTARGET_DARWIN ), _
 1225     (@"freebsd", FB_COMPTARGET_FREEBSD), _
 1226     (@"netbsd" , FB_COMPTARGET_NETBSD ), _
 1227     (@"openbsd", FB_COMPTARGET_OPENBSD), _
 1228     (@"xbox"   , FB_COMPTARGET_XBOX   )  _
 1229 }
 1230 
 1231 '' Architectures recognized when parsing GNU triplets (-target option)
 1232 dim shared as FBGNUARCHINFO gnuarchmap(0 to ...) => _
 1233 { _
 1234     (@"i386"   , FB_CPUTYPE_386            ), _
 1235     (@"i486"   , FB_CPUTYPE_486            ), _
 1236     (@"i586"   , FB_CPUTYPE_586            ), _
 1237     (@"i686"   , FB_CPUTYPE_686            ), _
 1238     (@"x86"    , FB_DEFAULT_CPUTYPE_X86    ), _
 1239     (@"x86_64" , FB_DEFAULT_CPUTYPE_X86_64 ), _
 1240     (@"amd64"  , FB_DEFAULT_CPUTYPE_X86_64 ), _
 1241     (@"armv6"  , FB_CPUTYPE_ARMV6          ), _
 1242     (@"armv7a" , FB_CPUTYPE_ARMV7A         ), _
 1243     (@"arm"    , FB_DEFAULT_CPUTYPE_ARM    ), _
 1244     (@"aarch64", FB_DEFAULT_CPUTYPE_AARCH64)  _
 1245 }
 1246 
 1247 '' Identify OS (FB_COMPTARGET_*) and architecture (FB_CPUTYPE_*) in a GNU
 1248 '' triplet string (gcc toolchain target name).
 1249 private sub hParseGnuTriplet _
 1250     ( _
 1251         byref arg as string, _
 1252         byval separator as integer, _
 1253         byref os as integer, _
 1254         byref cputype as integer _
 1255     )
 1256 
 1257     '' Search for OS, it be anywere in the triplet:
 1258     ''    mingw32              -> mingw
 1259     ''    arm-linux-gnueabihf  -> linux
 1260     ''    i686-w64-mingw32     -> mingw
 1261     ''    i686-pc-linux-gnu    -> linux
 1262     for i as integer = 0 to ubound( gnuosmap )
 1263         if( instr( arg, *gnuosmap(i).gnuid ) > 0 ) then
 1264             os = gnuosmap(i).os
 1265             exit for
 1266         end if
 1267     next
 1268 
 1269     '' If the triplet has at least two components (<arch>-<...>),
 1270     '' extract the first (the architecture and try to identify it.
 1271     if( separator > 0 ) then
 1272         var arch = left( arg, separator - 1 )
 1273         for i as integer = 0 to ubound( gnuarchmap )
 1274             if( arch = *gnuarchmap(i).gnuid ) then
 1275                 cputype = gnuarchmap(i).cputype
 1276                 exit for
 1277             end if
 1278         next
 1279     end if
 1280 
 1281 end sub
 1282 
 1283 type FBOSARCHINFO
 1284     targetid    as zstring ptr  '' -target option argument
 1285     os      as integer      '' FB_COMPTARGET_*
 1286     cputype     as integer      '' FB_CPUTYPE_*
 1287 end type
 1288 
 1289 '' Simple free-form arguments accepted by -target option
 1290 dim shared as FBOSARCHINFO fbosarchmap(0 to ...) => _
 1291 { _
 1292     _ '' win32/win64 refer to specific OS/arch combinations
 1293     (@"win32"  , FB_COMPTARGET_WIN32  , FB_DEFAULT_CPUTYPE_X86   ), _
 1294     (@"win64"  , FB_COMPTARGET_WIN32  , FB_DEFAULT_CPUTYPE_X86_64), _
 1295     _
 1296     _ '' OS given without arch, using the default arch, except for dos/xbox
 1297     _ ''  which only work with x86, so we can always default to x86 for them.
 1298     _ '' (these are supported for backwards compatibility with x86-only FB)
 1299     (@"dos"    , FB_COMPTARGET_DOS    , FB_DEFAULT_CPUTYPE_X86   ), _
 1300     (@"xbox"   , FB_COMPTARGET_XBOX   , FB_DEFAULT_CPUTYPE_X86   ), _
 1301     (@"cygwin" , FB_COMPTARGET_CYGWIN , FB_DEFAULT_CPUTYPE       ), _
 1302     (@"darwin" , FB_COMPTARGET_DARWIN , FB_DEFAULT_CPUTYPE       ), _
 1303     (@"freebsd", FB_COMPTARGET_FREEBSD, FB_DEFAULT_CPUTYPE       ), _
 1304     (@"linux"  , FB_COMPTARGET_LINUX  , FB_DEFAULT_CPUTYPE       ), _
 1305     (@"netbsd" , FB_COMPTARGET_NETBSD , FB_DEFAULT_CPUTYPE       ), _
 1306     (@"openbsd", FB_COMPTARGET_OPENBSD, FB_DEFAULT_CPUTYPE       )  _
 1307 }
 1308 
 1309 ''
 1310 '' Parse the -target option's argument.
 1311 ''
 1312 '' Examples:
 1313 ''    -target win32           ->    Windows + default x86 arch
 1314 ''    -target win64           ->    Windows + x86_64
 1315 ''    -target dos             ->    DOS + x86
 1316 ''    -target linux           ->    Linux + default arch
 1317 ''    -target linux-x86       ->    Linux + default x86 arch
 1318 ''    -target linux-x86_64    ->    Linux + x86_64
 1319 ''    ...
 1320 ''
 1321 '' The normal (non-standalone) build also accepts GNU triplets:
 1322 '' (the rough format is <arch>-<vendor>-<os> but it can vary a lot)
 1323 ''    -target i686-pc-linux-gnu      ->    Linux + i686
 1324 ''    -target arm-linux-gnueabihf    ->    Linux + default ARM arch
 1325 ''    -target x86_64-w64-mingw32     ->    Windows + x86_64
 1326 ''    ...
 1327 ''
 1328 '' The normal build uses the -target argument as prefix for binutils/gcc tools.
 1329 '' This allows fbc to work well with gcc/binutils cross-compiling toolchains,
 1330 '' for example: -target i686-pc-mingw32 causes it to use i686-pc-mingw32-ld
 1331 '' instead of the native ld.
 1332 ''
 1333 '' Something like -target win32 is mostly useful for the standalone build, where
 1334 '' binutils/gcc tools are arranged into the bin/win32/ld.exe etc. directory
 1335 '' layout. -target win32 is less useful for the normal build, because typically
 1336 '' binutils/gcc toolchains for cross-compiling to Windows are named something
 1337 '' like "i686-pc-mingw32", not just "win32". Nevertheless, even the normal build
 1338 '' should accept these options -- it can be useful for debugging purposes or
 1339 '' with the -print option. Furthermore, people (unnecessarily) specify -target
 1340 '' for native compilation (e.g. using -target linux on Linux), and this supports
 1341 '' that.
 1342 ''
 1343 '' This function should just do parsing, without any validation. It would be
 1344 '' nice if
 1345 ''    -target linux-x86_64
 1346 '' would just be the same as
 1347 ''    -target linux -arch x86_64
 1348 '' Thus, any validation should be done later when the command line has been
 1349 '' parsed completely.
 1350 ''
 1351 '' It's up to the caller to report an error if only one of OS/arch (but not
 1352 '' both) could be identified.
 1353 ''
 1354 private sub hParseTargetArg _
 1355     ( _
 1356         byref arg as string, _
 1357         byref os as integer, _
 1358         byref cputype as integer, _
 1359         byref is_gnu_triplet as integer _
 1360     )
 1361 
 1362     os = -1
 1363     cputype = -1
 1364     is_gnu_triplet = FALSE
 1365 
 1366     '' Case-insensitive so "-target WIN32" etc. works too
 1367     var lcasearg = lcase( arg )
 1368 
 1369     '' Check for simple arguments (dos, linux, win32, etc.)
 1370     for i as integer = 0 to ubound( fbosarchmap )
 1371         if( lcasearg = *fbosarchmap(i).targetid ) then
 1372             os = fbosarchmap(i).os
 1373             cputype = fbosarchmap(i).cputype
 1374             exit sub
 1375         end if
 1376     next
 1377 
 1378     '' <os>-<cpufamily>
 1379     var separator = instr( arg, "-" )
 1380     if( separator > 0 ) then
 1381         os = fbIdentifyOs( left( lcasearg, separator - 1 ) )
 1382         cputype = fbCpuTypeFromCpuFamilyId( right( lcasearg, len( lcasearg ) - separator ) )
 1383     end if
 1384 
 1385     '' Normal build: Check for GNU triplets, if the above checks failed.
 1386     #ifndef ENABLE_STANDALONE
 1387         if( (os < 0) and (cputype < 0) ) then
 1388             hParseGnuTriplet( arg, separator, os, cputype )
 1389             is_gnu_triplet = TRUE
 1390         end if
 1391     #endif
 1392 end sub
 1393 
 1394 enum
 1395     OPT_A = 0
 1396     OPT_ARCH
 1397     OPT_ASM
 1398     OPT_B
 1399     OPT_C
 1400     OPT_CKEEPOBJ
 1401     OPT_D
 1402     OPT_DLL
 1403     OPT_DYLIB
 1404     OPT_E
 1405     OPT_EARRAY
 1406     OPT_EASSERT
 1407     OPT_EDEBUG
 1408     OPT_EDEBUGINFO
 1409     OPT_ELOCATION
 1410     OPT_ENULLPTR
 1411     OPT_EX
 1412     OPT_EXX
 1413     OPT_EXPORT
 1414     OPT_FORCELANG
 1415     OPT_FPMODE
 1416     OPT_FPU
 1417     OPT_G
 1418     OPT_GEN
 1419     OPT_HELP
 1420     OPT_I
 1421     OPT_INCLUDE
 1422     OPT_L
 1423     OPT_LANG
 1424     OPT_LIB
 1425     OPT_M
 1426     OPT_MAP
 1427     OPT_MAXERR
 1428     OPT_MT
 1429     OPT_NODEFLIBS
 1430     OPT_NOERRLINE
 1431     OPT_NOOBJINFO
 1432     OPT_NOSTRIP
 1433     OPT_O
 1434     OPT_OPTIMIZE
 1435     OPT_P
 1436     OPT_PIC
 1437     OPT_PP
 1438     OPT_PREFIX
 1439     OPT_PRINT
 1440     OPT_PROFILE
 1441     OPT_R
 1442     OPT_RKEEPASM
 1443     OPT_RR
 1444     OPT_RRKEEPASM
 1445     OPT_S
 1446     OPT_SHOWINCLUDES
 1447     OPT_STATIC
 1448     OPT_STRIP
 1449     OPT_T
 1450     OPT_TARGET
 1451     OPT_TITLE
 1452     OPT_V
 1453     OPT_VEC
 1454     OPT_VERSION
 1455     OPT_W
 1456     OPT_WA
 1457     OPT_WC
 1458     OPT_WL
 1459     OPT_X
 1460     OPT_Z
 1461     OPT__COUNT
 1462 end enum
 1463 
 1464 dim shared as integer option_takes_argument(0 to (OPT__COUNT - 1)) = _
 1465 { _
 1466     TRUE , _ '' OPT_A
 1467     TRUE , _ '' OPT_ARCH
 1468     TRUE , _ '' OPT_ASM
 1469     TRUE , _ '' OPT_B
 1470     FALSE, _ '' OPT_C
 1471     FALSE, _ '' OPT_CKEEPOBJ
 1472     TRUE , _ '' OPT_D
 1473     FALSE, _ '' OPT_DLL
 1474     FALSE, _ '' OPT_DYLIB
 1475     FALSE, _ '' OPT_E
 1476     FALSE, _ '' OPT_EARRAY
 1477     FALSE, _ '' OPT_EASSERT
 1478     FALSE, _ '' OPT_EDEBUG
 1479     FALSE, _ '' OPT_EDEBUGINFO
 1480     FALSE, _ '' OPT_ELOCATION
 1481     FALSE, _ '' OPT_ENULLPTR
 1482     FALSE, _ '' OPT_EX
 1483     FALSE, _ '' OPT_EXX
 1484     FALSE, _ '' OPT_EXPORT
 1485     TRUE,  _ '' OPT_FORCELANG
 1486     TRUE , _ '' OPT_FPMODE
 1487     TRUE , _ '' OPT_FPU
 1488     FALSE, _ '' OPT_G
 1489     TRUE , _ '' OPT_GEN
 1490     FALSE, _ '' OPT_HELP
 1491     TRUE , _ '' OPT_I
 1492     TRUE , _ '' OPT_INCLUDE
 1493     TRUE , _ '' OPT_L
 1494     TRUE , _ '' OPT_LANG
 1495     FALSE, _ '' OPT_LIB
 1496     TRUE , _ '' OPT_M
 1497     TRUE , _ '' OPT_MAP
 1498     TRUE , _ '' OPT_MAXERR
 1499     FALSE, _ '' OPT_MT
 1500     FALSE, _ '' OPT_NODEFLIBS
 1501     FALSE, _ '' OPT_NOERRLINE
 1502     FALSE, _ '' OPT_NOOBJINFO
 1503     FALSE, _ '' OPT_NOSTRIP
 1504     TRUE , _ '' OPT_O
 1505     TRUE , _ '' OPT_OPTIMIZE
 1506     TRUE , _ '' OPT_P
 1507     FALSE, _ '' OPT_PIC
 1508     FALSE, _ '' OPT_PP
 1509     TRUE , _ '' OPT_PREFIX
 1510     TRUE , _ '' OPT_PRINT
 1511     FALSE, _ '' OPT_PROFILE
 1512     FALSE, _ '' OPT_R
 1513     FALSE, _ '' OPT_RKEEPASM
 1514     FALSE, _ '' OPT_RR
 1515     FALSE, _ '' OPT_RRKEEPASM
 1516     TRUE , _ '' OPT_S
 1517     FALSE, _ '' OPT_SHOWINCLUDES
 1518     FALSE, _ '' OPT_STATIC
 1519     FALSE, _ '' OPT_STRIP
 1520     TRUE , _ '' OPT_T
 1521     TRUE , _ '' OPT_TARGET
 1522     TRUE , _ '' OPT_TITLE
 1523     FALSE, _ '' OPT_V
 1524     TRUE , _ '' OPT_VEC
 1525     FALSE, _ '' OPT_VERSION
 1526     TRUE , _ '' OPT_W
 1527     TRUE , _ '' OPT_WA
 1528     TRUE , _ '' OPT_WC
 1529     TRUE , _ '' OPT_WL
 1530     TRUE , _ '' OPT_X
 1531     TRUE   _ '' OPT_Z
 1532 }
 1533 
 1534 private sub handleOpt(byval optid as integer, byref arg as string)
 1535     select case as const (optid)
 1536     case OPT_A
 1537         fbcAddObj( arg )
 1538 
 1539     case OPT_ARCH
 1540         fbc.cputype_is_native = (arg = "native")
 1541         fbc.cputype = fbIdentifyFbcArch( arg )
 1542         if( fbc.cputype < 0 ) then
 1543             hFatalInvalidOption( "-arch " + arg )
 1544         end if
 1545 
 1546     case OPT_ASM
 1547         select case( arg )
 1548         case "att"
 1549             fbc.asmsyntax = FB_ASMSYNTAX_ATT
 1550         case "intel"
 1551             fbc.asmsyntax = FB_ASMSYNTAX_INTEL
 1552         case else
 1553             hFatalInvalidOption( arg )
 1554         end select
 1555 
 1556     case OPT_B
 1557         hAddBas( arg )
 1558 
 1559     case OPT_C
 1560         '' -c changes the output type to from exe/lib/dll to object,
 1561         '' overwriting previous -dll, -lib or the default exe.
 1562         fbSetOption( FB_COMPOPT_OUTTYPE, FB_OUTTYPE_OBJECT )
 1563         fbc.keepobj = TRUE
 1564 
 1565     case OPT_CKEEPOBJ
 1566         fbc.keepobj = TRUE
 1567 
 1568     case OPT_D
 1569         fbAddPreDefine(arg)
 1570 
 1571     case OPT_DLL, OPT_DYLIB
 1572         fbSetOption( FB_COMPOPT_OUTTYPE, FB_OUTTYPE_DYNAMICLIB )
 1573 
 1574     case OPT_E
 1575         fbSetOption( FB_COMPOPT_ERRORCHECK, TRUE )
 1576 
 1577     case OPT_EARRAY
 1578         fbSetOption( FB_COMPOPT_ARRAYBOUNDCHECK, TRUE )
 1579 
 1580     case OPT_EASSERT
 1581         fbSetOption( FB_COMPOPT_ASSERTIONS, TRUE )
 1582 
 1583     case OPT_EDEBUG
 1584         fbSetOption( FB_COMPOPT_DEBUG, TRUE )
 1585 
 1586     case OPT_EDEBUGINFO
 1587         fbSetOption( FB_COMPOPT_DEBUGINFO, TRUE )
 1588 
 1589     case OPT_ELOCATION
 1590         fbSetOption( FB_COMPOPT_ERRLOCATION, TRUE )
 1591 
 1592     case OPT_ENULLPTR
 1593         fbSetOption( FB_COMPOPT_NULLPTRCHECK, TRUE )
 1594 
 1595     case OPT_EX
 1596         fbSetOption( FB_COMPOPT_ERRORCHECK, TRUE )
 1597         fbSetOption( FB_COMPOPT_RESUMEERROR, TRUE )
 1598 
 1599     case OPT_EXX
 1600         fbSetOption( FB_COMPOPT_ERRORCHECK, TRUE )
 1601         fbSetOption( FB_COMPOPT_RESUMEERROR, TRUE )
 1602         fbSetOption( FB_COMPOPT_EXTRAERRCHECK, TRUE )
 1603         fbSetOption( FB_COMPOPT_ERRLOCATION, TRUE )
 1604         fbSetOption( FB_COMPOPT_ARRAYBOUNDCHECK, TRUE )
 1605         fbSetOption( FB_COMPOPT_NULLPTRCHECK, TRUE )
 1606 
 1607     case OPT_EXPORT
 1608         fbSetOption( FB_COMPOPT_EXPORT, TRUE )
 1609 
 1610     case OPT_FORCELANG
 1611         dim as integer value = fbGetLangId(strptr(arg))
 1612         if( value = FB_LANG_INVALID ) then
 1613             hFatalInvalidOption( arg )
 1614         end if
 1615 
 1616         fbSetOption( FB_COMPOPT_LANG, value )
 1617         fbSetOption( FB_COMPOPT_FORCELANG, TRUE )
 1618         fbc.objinf.lang = value
 1619 
 1620     case OPT_FPMODE
 1621         dim as integer value = any
 1622 
 1623         select case ucase(arg)
 1624         case "PRECISE"
 1625             value = FB_FPMODE_PRECISE
 1626         case "FAST"
 1627             value = FB_FPMODE_FAST
 1628         case else
 1629             hFatalInvalidOption( arg )
 1630         end select
 1631 
 1632         fbSetOption( FB_COMPOPT_FPMODE, value )
 1633 
 1634     case OPT_FPU
 1635         dim as integer value = any
 1636 
 1637         select case ucase(arg)
 1638         case "X87", "FPU"
 1639             value = FB_FPUTYPE_FPU
 1640         case "SSE"
 1641             value = FB_FPUTYPE_SSE
 1642         case else
 1643             hFatalInvalidOption( arg )
 1644         end select
 1645 
 1646         fbSetOption( FB_COMPOPT_FPUTYPE, value )
 1647 
 1648     case OPT_G
 1649         fbSetOption( FB_COMPOPT_DEBUG, TRUE )
 1650         fbSetOption( FB_COMPOPT_DEBUGINFO, TRUE )
 1651         fbSetOption( FB_COMPOPT_ASSERTIONS, TRUE )
 1652 
 1653     case OPT_GEN
 1654         select case( lcase( arg ) )
 1655         case "gas"
 1656             fbc.backend = FB_BACKEND_GAS
 1657         case "gcc"
 1658             fbc.backend = FB_BACKEND_GCC
 1659         case "llvm"
 1660             fbc.backend = FB_BACKEND_LLVM
 1661         case else
 1662             hFatalInvalidOption( arg )
 1663         end select
 1664 
 1665     case OPT_HELP
 1666         fbc.showhelp = TRUE
 1667 
 1668     case OPT_I
 1669         fbAddIncludePath(pathStripDiv(arg))
 1670 
 1671     case OPT_INCLUDE
 1672         fbAddPreInclude(arg)
 1673 
 1674     case OPT_L
 1675         strsetAdd(@fbc.libs, arg, FALSE)
 1676 
 1677     case OPT_LANG
 1678         dim as integer value = fbGetLangId( strptr(arg) )
 1679         if( value = FB_LANG_INVALID ) then
 1680             hFatalInvalidOption( arg )
 1681         end if
 1682 
 1683         fbSetOption( FB_COMPOPT_LANG, value )
 1684         fbc.objinf.lang = value
 1685 
 1686     case OPT_LIB
 1687         fbSetOption( FB_COMPOPT_OUTTYPE, FB_OUTTYPE_STATICLIB )
 1688 
 1689     case OPT_M
 1690         fbc.mainname = arg
 1691         fbc.mainset = TRUE
 1692 
 1693     case OPT_MAP
 1694         fbc.mapfile = arg
 1695 
 1696     case OPT_MAXERR
 1697         dim as integer value = any
 1698 
 1699         if( arg = "inf" ) then
 1700             value = FB_ERR_INFINITE
 1701         else
 1702             value = clng( arg )
 1703             if( value <= 0 ) then
 1704                 hFatalInvalidOption( arg )
 1705             end if
 1706         end if
 1707 
 1708         fbSetOption( FB_COMPOPT_MAXERRORS, value )
 1709 
 1710     case OPT_MT
 1711         fbSetOption( FB_COMPOPT_MULTITHREADED, TRUE )
 1712         fbc.objinf.mt = TRUE
 1713 
 1714     case OPT_NODEFLIBS
 1715         fbc.nodeflibs = TRUE
 1716 
 1717     case OPT_NOERRLINE
 1718         fbSetOption( FB_COMPOPT_SHOWERROR, FALSE )
 1719 
 1720     case OPT_NOOBJINFO
 1721         fbSetOption( FB_COMPOPT_OBJINFO, FALSE )
 1722 
 1723     case OPT_NOSTRIP
 1724         fbc.stripsymbols = FALSE
 1725 
 1726     case OPT_O
 1727         '' Error if there already is an -o waiting to be assigned
 1728         hCheckWaitingObjfile( )
 1729 
 1730         '' Assign it to the last module, if it doesn't have an
 1731         '' -o filename yet, or store it for later otherwise.
 1732         if( fbc.lastmodule ) then
 1733             *fbc.lastmodule->objfile = arg
 1734             fbc.lastmodule->is_custom_objfile = TRUE
 1735         else
 1736             fbc.objfile = arg
 1737         end if
 1738 
 1739     case OPT_OPTIMIZE
 1740         dim as integer value = any
 1741 
 1742         if (arg = "max") then
 1743             value = 3
 1744         else
 1745             value = clng( arg )
 1746             if (value < 0) then
 1747                 value = 0
 1748             elseif (value > 3) then
 1749                 value = 3
 1750             end if
 1751         end if
 1752 
 1753         fbSetOption( FB_COMPOPT_OPTIMIZELEVEL, value )
 1754 
 1755     case OPT_P
 1756         strsetAdd(@fbc.libpaths, pathStripDiv(arg), FALSE)
 1757 
 1758     case OPT_PIC
 1759         fbSetOption( FB_COMPOPT_PIC, TRUE )
 1760 
 1761     case OPT_PP
 1762         '' -pp doesn't change the output type, but like -r we want to
 1763         '' stop fbc very early.
 1764         fbSetOption( FB_COMPOPT_PPONLY, TRUE )
 1765         fbc.emitasmonly = TRUE
 1766 
 1767     case OPT_PREFIX
 1768         fbc.prefix = pathStripDiv(arg)
 1769         hReplaceSlash( fbc.prefix, asc( FB_HOST_PATHDIV ) )
 1770 
 1771     case OPT_PRINT
 1772         select case( arg )
 1773         case "host"   : fbc.print = PRINT_HOST
 1774         case "target" : fbc.print = PRINT_TARGET
 1775         case "x"      : fbc.print = PRINT_X
 1776         case "fblibdir" : fbc.print = PRINT_FBLIBDIR
 1777         case "sha-1"  : fbc.print = PRINT_SHA1
 1778         case else
 1779             hFatalInvalidOption( arg )
 1780         end select
 1781 
 1782     case OPT_PROFILE
 1783         fbSetOption( FB_COMPOPT_PROFILE, TRUE )
 1784 
 1785     case OPT_R
 1786         '' -r changes the output type to .o, like -c, i.e. -m may have
 1787         '' to be used to mark the main module, just like -c.
 1788         fbSetOption( FB_COMPOPT_OUTTYPE, FB_OUTTYPE_OBJECT )
 1789         '' -r will stop fbc earlier than -c though.
 1790         fbc.emitasmonly = TRUE
 1791         fbc.keepasm = TRUE
 1792 
 1793     case OPT_RKEEPASM
 1794         fbc.keepasm = TRUE
 1795 
 1796     case OPT_RR
 1797         fbSetOption( FB_COMPOPT_OUTTYPE, FB_OUTTYPE_OBJECT )
 1798         fbc.emitfinalasmonly = TRUE
 1799         fbc.keepfinalasm = TRUE
 1800 
 1801     case OPT_RRKEEPASM
 1802         fbc.keepfinalasm = TRUE
 1803 
 1804     case OPT_S
 1805         fbc.subsystem = arg
 1806         select case( arg )
 1807             case "gui" : fbSetOption( FB_COMPOPT_MODEVIEW, FB_MODEVIEW_GUI )
 1808         end select
 1809 
 1810     case OPT_SHOWINCLUDES
 1811         fbSetOption( FB_COMPOPT_SHOWINCLUDES, TRUE )
 1812 
 1813     case OPT_STATIC
 1814         fbc.staticlink = TRUE
 1815 
 1816     case OPT_STRIP
 1817         fbc.stripsymbols = TRUE
 1818 
 1819     case OPT_T
 1820         fbSetOption( FB_COMPOPT_STACKSIZE, clng( arg ) * 1024 )
 1821 
 1822     case OPT_TARGET
 1823         dim as integer os, cputype, is_gnu_triplet
 1824         hParseTargetArg( arg, os, cputype, is_gnu_triplet )
 1825 
 1826         if( (os < 0) or (cputype < 0) ) then
 1827             hFatalInvalidOption( arg )
 1828         end if
 1829 
 1830         '' Store the OS/cputype, overwriting the values from any
 1831         '' previous -target options.
 1832         fbSetOption( FB_COMPOPT_TARGET, os )
 1833         fbSetOption( FB_COMPOPT_CPUTYPE, cputype )
 1834 
 1835         #ifndef ENABLE_STANDALONE
 1836             '' Normal build: Store the original -target argument
 1837             '' for use as prefix for binutils/gcc tools, but only
 1838             '' when cross-compiling or if it's really a GNU triplet.
 1839             if( (os <> FB_DEFAULT_TARGET) or _
 1840                 (cputype <> FB_DEFAULT_CPUTYPE) or _
 1841                 is_gnu_triplet ) then
 1842                 fbc.target = arg
 1843                 fbc.targetprefix = fbc.target + "-"
 1844             end if
 1845         #endif
 1846 
 1847     case OPT_TITLE
 1848         fbc.xbe_title = arg
 1849 
 1850     case OPT_V
 1851         fbc.verbose = TRUE
 1852 
 1853     case OPT_VEC
 1854         dim as integer value = any
 1855 
 1856         select case (ucase(arg))
 1857         case "NONE", "0"
 1858             value = FB_VECTORIZE_NONE
 1859         case "1"
 1860             value = FB_VECTORIZE_NORMAL
 1861         case "2"
 1862             value = FB_VECTORIZE_INTRATREE
 1863         case else
 1864             hFatalInvalidOption( arg )
 1865         end select
 1866 
 1867         fbSetOption( FB_COMPOPT_VECTORIZE, value )
 1868 
 1869     case OPT_VERSION
 1870         fbc.showversion = TRUE
 1871 
 1872     case OPT_W
 1873         dim as integer value = FB_WARNINGMSGS_LOWEST_LEVEL - 1
 1874 
 1875         select case (arg)
 1876         case "all"
 1877             value = FB_WARNINGMSGS_LOWEST_LEVEL
 1878 
 1879         case "none"
 1880             value = FB_WARNINGMSGS_HIGHEST_LEVEL + 1
 1881 
 1882         case "param"
 1883             fbSetOption( FB_COMPOPT_PEDANTICCHK, _
 1884                          fbGetOption( FB_COMPOPT_PEDANTICCHK ) or FB_PDCHECK_PARAMMODE )
 1885 
 1886         case "escape"
 1887             fbSetOption( FB_COMPOPT_PEDANTICCHK, _
 1888                          fbGetOption( FB_COMPOPT_PEDANTICCHK ) or FB_PDCHECK_ESCSEQ )
 1889 
 1890         case "next"
 1891             fbSetOption( FB_COMPOPT_PEDANTICCHK, _
 1892                          fbGetOption( FB_COMPOPT_PEDANTICCHK ) or FB_PDCHECK_NEXTVAR )
 1893 
 1894         case "signedness"
 1895             fbSetOption( FB_COMPOPT_PEDANTICCHK, _
 1896                          fbGetOption( FB_COMPOPT_PEDANTICCHK ) or FB_PDCHECK_SIGNEDNESS )
 1897 
 1898         case "constness"
 1899             fbSetOption( FB_COMPOPT_PEDANTICCHK, _
 1900                          fbGetOption( FB_COMPOPT_PEDANTICCHK ) or FB_PDCHECK_CONSTNESS )
 1901             value = FB_WARNINGMSGS_LOWEST_LEVEL
 1902 
 1903         case "funcptr"
 1904             fbSetOption( FB_COMPOPT_PEDANTICCHK, _
 1905                          fbGetOption( FB_COMPOPT_PEDANTICCHK ) or FB_PDCHECK_CASTFUNCPTR )
 1906             value = FB_WARNINGMSGS_LOWEST_LEVEL
 1907 
 1908         case "pedantic"
 1909             fbSetOption( FB_COMPOPT_PEDANTICCHK, FB_PDCHECK_DEFAULT )
 1910             if( value > FB_WARNINGMSGS_DEFAULT_LEVEL ) then
 1911                 value = FB_WARNINGMSGS_DEFAULT_LEVEL
 1912             end if
 1913 
 1914         case else
 1915             value = clng( arg )
 1916         end select
 1917 
 1918         if( value >= FB_WARNINGMSGS_LOWEST_LEVEL ) then
 1919             fbSetOption( FB_COMPOPT_WARNINGLEVEL, value )
 1920         end if
 1921 
 1922     case OPT_WA
 1923         fbc.extopt.gas += " " + hReplace( arg, ",", " " ) + " "
 1924 
 1925     case OPT_WC
 1926         fbc.extopt.gcc += " " + hReplace( arg, ",", " " ) + " "
 1927 
 1928     case OPT_WL
 1929         fbc.extopt.ld += " " + hReplace( arg, ",", " " ) + " "
 1930 
 1931     case OPT_X
 1932         fbc.outname = arg
 1933 
 1934     case OPT_Z
 1935         select case( lcase( arg ) )
 1936         case "gosub-setjmp"
 1937             fbSetOption( FB_COMPOPT_GOSUBSETJMP, TRUE )
 1938         case "valist-as-ptr"
 1939             fbSetOption( FB_COMPOPT_VALISTASPTR, TRUE )
 1940         case else
 1941             hFatalInvalidOption( arg )
 1942         end select
 1943 
 1944     end select
 1945 end sub
 1946 
 1947 private function parseOption(byval opt as zstring ptr) as integer
 1948     #macro CHECK(opttext, optid)
 1949         if (*opt = opttext) then
 1950             return optid
 1951         end if
 1952     #endmacro
 1953 
 1954     #macro ONECHAR(optid)
 1955         if (cptr(ubyte ptr, opt)[1] = 0) then
 1956             return optid
 1957         end if
 1958     #endmacro
 1959 
 1960     select case as const (cptr(ubyte ptr, opt)[0])
 1961     case asc("a")
 1962         ONECHAR(OPT_A)
 1963         CHECK("arch", OPT_ARCH)
 1964         CHECK("asm", OPT_ASM)
 1965 
 1966     case asc("b")
 1967         ONECHAR(OPT_B)
 1968 
 1969     case asc("c")
 1970         ONECHAR(OPT_C)
 1971 
 1972     case asc("C")
 1973         ONECHAR(OPT_CKEEPOBJ)
 1974 
 1975     case asc("d")
 1976         ONECHAR(OPT_D)
 1977         CHECK("dll", OPT_DLL)
 1978         CHECK("dylib", OPT_DYLIB)
 1979 
 1980     case asc("e")
 1981         ONECHAR(OPT_E)
 1982         CHECK("ex", OPT_EX)
 1983         CHECK("earray", OPT_EARRAY)
 1984         CHECK("eassert", OPT_EASSERT)
 1985         CHECK("edebug", OPT_EDEBUG)
 1986         CHECK("edebuginfo", OPT_EDEBUGINFO)
 1987         CHECK("elocation", OPT_ELOCATION)
 1988         CHECK("enullptr", OPT_ENULLPTR)
 1989         CHECK("exx", OPT_EXX)
 1990         CHECK("export", OPT_EXPORT)
 1991 
 1992     case asc("f")
 1993         CHECK("forcelang", OPT_FORCELANG)
 1994         CHECK("fpmode", OPT_FPMODE)
 1995         CHECK("fpu", OPT_FPU)
 1996 
 1997     case asc("g")
 1998         ONECHAR(OPT_G)
 1999         CHECK("gen", OPT_GEN)
 2000 
 2001     case asc( "h" )
 2002         CHECK( "help", OPT_HELP )
 2003 
 2004     case asc("i")
 2005         ONECHAR(OPT_I)
 2006         CHECK("include", OPT_INCLUDE)
 2007 
 2008     case asc("l")
 2009         ONECHAR(OPT_L)
 2010         CHECK("lang", OPT_LANG)
 2011         CHECK("lib", OPT_LIB)
 2012 
 2013     case asc("m")
 2014         ONECHAR(OPT_M)
 2015         CHECK("map", OPT_MAP)
 2016         CHECK("maxerr", OPT_MAXERR)
 2017         CHECK("mt", OPT_MT)
 2018 
 2019     case asc("n")
 2020         CHECK("noerrline", OPT_NOERRLINE)
 2021         CHECK("nodeflibs", OPT_NODEFLIBS)
 2022         CHECK("noobjinfo", OPT_NOOBJINFO)
 2023         CHECK("nostrip", OPT_NOSTRIP)
 2024 
 2025     case asc("o")
 2026         ONECHAR(OPT_O)
 2027 
 2028     case asc("O")
 2029         ONECHAR(OPT_OPTIMIZE)
 2030 
 2031     case asc("p")
 2032         ONECHAR(OPT_P)
 2033         CHECK("pic", OPT_PIC)
 2034         CHECK("pp", OPT_PP)
 2035         CHECK("prefix", OPT_PREFIX)
 2036         CHECK("print", OPT_PRINT)
 2037         CHECK("profile", OPT_PROFILE)
 2038 
 2039     case asc("r")
 2040         ONECHAR(OPT_R)
 2041         CHECK("rr", OPT_RR)
 2042 
 2043     case asc("R")
 2044         ONECHAR(OPT_RKEEPASM)
 2045         CHECK("RR", OPT_RRKEEPASM)
 2046 
 2047     case asc("s")
 2048         ONECHAR(OPT_S)
 2049         CHECK("showincludes", OPT_SHOWINCLUDES)
 2050         CHECK("static", OPT_STATIC)
 2051         CHECK("strip", OPT_STRIP)
 2052 
 2053     case asc("t")
 2054         ONECHAR(OPT_T)
 2055         CHECK("target", OPT_TARGET)
 2056         CHECK("title", OPT_TITLE)
 2057 
 2058     case asc("v")
 2059         ONECHAR(OPT_V)
 2060         CHECK("vec", OPT_VEC)
 2061         CHECK("version", OPT_VERSION)
 2062 
 2063     case asc("w")
 2064         ONECHAR(OPT_W)
 2065 
 2066     case asc("W")
 2067         CHECK("Wa", OPT_WA)
 2068         CHECK("Wl", OPT_WL)
 2069         CHECK("Wc", OPT_WC)
 2070 
 2071     case asc("x")
 2072         ONECHAR(OPT_X)
 2073 
 2074     case asc("z")
 2075         ONECHAR(OPT_Z)
 2076 
 2077     case asc( "-" )
 2078         CHECK( "-version", OPT_VERSION )
 2079         CHECK( "-help", OPT_HELP )
 2080 
 2081     end select
 2082 
 2083     return -1
 2084 end function
 2085 
 2086 declare sub parseArgsFromFile(byref filename as string)
 2087 
 2088 private sub handleArg(byref arg as string)
 2089     '' If the previous option wants this argument as parameter,
 2090     '' call the handler with it, now that it's known.
 2091     '' Note: Anything is accepted, even if it starts with '-' or '@'.
 2092     if (fbc.optid >= 0) then
 2093         '' Complain about empty next argument
 2094         if (len(arg) = 0) then
 2095             hFatalInvalidOption( arg )
 2096         end if
 2097 
 2098         handleOpt(fbc.optid, arg)
 2099         fbc.optid = -1
 2100         return
 2101     end if
 2102 
 2103     if (len(arg) = 0) then
 2104         '' Ignore empty argument
 2105         return
 2106     end if
 2107 
 2108     select case (arg[0])
 2109     case asc("-")
 2110         dim as zstring ptr opt = strptr(arg) + 1
 2111 
 2112         '' Complain about '-' only
 2113         if (cptr(ubyte ptr, opt)[0] = 0) then
 2114             '' Incomplete command line option
 2115             hFatalInvalidOption( arg )
 2116         end if
 2117 
 2118         '' Parse the option after the '-'
 2119         dim as integer optid = parseOption(opt)
 2120         if (optid < 0) then
 2121             '' Unrecognized command line option
 2122             hFatalInvalidOption( arg )
 2123         end if
 2124 
 2125         '' Does this option take a parameter?
 2126         if (option_takes_argument(optid)) then
 2127             '' Delay handling it, until the next argument is known.
 2128             fbc.optid = optid
 2129         else
 2130             '' Handle this option now
 2131             handleOpt(optid, arg)
 2132         end if
 2133 
 2134     case asc("@")
 2135         '' Maximum nesting/recursion level
 2136         const MAX_LEVELS = 128
 2137         static as integer reclevel = 0
 2138 
 2139         if (reclevel > MAX_LEVELS) then
 2140             '' Options file nesting level too deep (recursion?)
 2141             errReportEx( FB_ERRMSG_RECLEVELTOODEEP, arg, -1 )
 2142             fbcEnd(1)
 2143         end if
 2144 
 2145         '' Cut off the '@' at the front to get just the file name
 2146         arg = right(arg, len(arg) - 1)
 2147 
 2148         '' Complain about '@' only
 2149         if (len(arg) = 0) then
 2150             '' Missing file name after '@'
 2151             hFatalInvalidOption( arg )
 2152         end if
 2153 
 2154         '' Recursively read in the additional options from the file
 2155         reclevel += 1
 2156         parseArgsFromFile(arg)
 2157         reclevel -= 1
 2158 
 2159     case else
 2160         '' Input file, get its extension to determine what it is
 2161         dim as string ext = hGetFileExt(arg)
 2162 
 2163         #if defined(__FB_WIN32__) or _
 2164             defined(__FB_DOS__) or _
 2165             defined(__FB_CYGWIN__)
 2166             '' For case in-sensitive file systems
 2167             ext = lcase(ext)
 2168         #endif
 2169 
 2170         select case (ext)
 2171         case "bas"
 2172             hAddBas( arg )
 2173 
 2174         case "o"
 2175             fbcAddObj( arg )
 2176 
 2177         case "a"
 2178             strlistAppend( @fbc.libfiles, arg )
 2179 
 2180         case "rc", "res"
 2181             hSetIofile( listNewNode( @fbc.rcs ), arg, TRUE )
 2182 
 2183         case "xpm"
 2184             '' Can have only one .xpm, or the fb_program_icon
 2185             '' symbol will be duplicated
 2186             if( len( fbc.xpm.srcfile ) > 0 ) then
 2187                 hFatalInvalidOption( arg )
 2188             end if
 2189 
 2190             hSetIofile( @fbc.xpm, arg, TRUE )
 2191 
 2192         case else
 2193             '' Input file without or with unknown extension
 2194             hFatalInvalidOption( arg )
 2195 
 2196         end select
 2197     end select
 2198 end sub
 2199 
 2200 private sub parseArgsFromFile(byref filename as string)
 2201     dim as integer f = freefile()
 2202     if (open(filename, for input, as #f)) then
 2203         errReportEx( FB_ERRMSG_FILEACCESSERROR, filename, -1 )
 2204         fbcEnd(1)
 2205     end if
 2206 
 2207     dim as string args
 2208     dim as string arg
 2209 
 2210     while (eof(f) = FALSE)
 2211         line input #f, args
 2212         args = trim(args)
 2213 
 2214         '' Parse the line containing command line arguments,
 2215         '' separated by spaces. Double- and single-quoted strings
 2216         '' are handled too, but nothing else.
 2217         do
 2218             dim as integer length = len(args)
 2219             if (length = 0) then
 2220                 exit do
 2221             end if
 2222 
 2223             dim as integer i = 0
 2224             dim as integer quotech = 0
 2225 
 2226             while (i < length)
 2227                 dim as integer ch = args[i]
 2228 
 2229                 select case as const (ch)
 2230                 case asc(" ")
 2231                     if (quotech = 0) then
 2232                         exit while
 2233                     end if
 2234 
 2235                 case asc(""""), asc("'")
 2236                     if (quotech = ch) then
 2237                         '' String closed
 2238                         quotech = 0
 2239                     elseif (quotech = 0) then
 2240                         '' String opened
 2241                         quotech = ch
 2242                     end if
 2243 
 2244                 end select
 2245 
 2246                 i += 1
 2247             wend
 2248 
 2249             if (i = 0) then
 2250                 '' Just space, skip it
 2251                 i = 1
 2252             else
 2253                 arg = left(args, i)
 2254                 arg = trim(arg)
 2255                 arg = strUnquote(arg)
 2256                 handleArg(arg)
 2257             end if
 2258 
 2259             args = right(args, length - i)
 2260         loop
 2261     wend
 2262 
 2263     close #f
 2264 end sub
 2265 
 2266 private function hTargetNeedsPIC( ) as integer
 2267     function = FALSE
 2268     if( fbGetCpuFamily( ) <> FB_CPUFAMILY_X86 ) then
 2269         select case as const( fbGetOption( FB_COMPOPT_TARGET ) )
 2270         case FB_COMPTARGET_LINUX, FB_COMPTARGET_FREEBSD, _
 2271              FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD
 2272             function = TRUE
 2273         end select
 2274     end if
 2275 end function
 2276 
 2277 private sub hParseArgs( byval argc as integer, byval argv as zstring ptr ptr )
 2278     fbc.optid = -1
 2279 
 2280     '' Note: ignoring argv[0], assuming it's the path used to run fbc
 2281     dim as string arg
 2282     for i as integer = 1 to (argc - 1)
 2283         arg = *argv[i]
 2284         handleArg(arg)
 2285     next
 2286 
 2287     '' Waiting for argument to an option? If the user did something like
 2288     '' 'fbc foo.bas -o' this shows the error.
 2289     if (fbc.optid >= 0) then
 2290         '' Missing argument for command line option
 2291         hFatalInvalidOption( *argv[argc - 1] )
 2292     end if
 2293 
 2294     '' In case there was an '-o <file>', but no corresponding input file,
 2295     '' this will report the error.
 2296     hCheckWaitingObjfile( )
 2297 
 2298     ''
 2299     '' Check for incompatible options etc.
 2300     ''
 2301 
 2302     if ( fbGetOption( FB_COMPOPT_FPUTYPE ) = FB_FPUTYPE_FPU ) then
 2303         if( fbGetOption( FB_COMPOPT_VECTORIZE ) >= FB_VECTORIZE_NORMAL ) or _
 2304             ( fbGetOption( FB_COMPOPT_FPMODE ) = FB_FPMODE_FAST ) then
 2305                 errReportEx( FB_ERRMSG_OPTIONREQUIRESSSE, "", -1 )
 2306             fbcEnd( 1 )
 2307         end if
 2308     end if
 2309 
 2310     '' 1. The compiler (fb.bas) starts with default target settings for
 2311     ''    native compilation.
 2312 
 2313     '' 2. -target option handling has already switched the target if given.
 2314 
 2315     '' 3. -arch overrides any other arch settings.
 2316     if( fbc.cputype >= 0 ) then
 2317         fbSetOption( FB_COMPOPT_CPUTYPE, fbc.cputype )
 2318     end if
 2319 
 2320     '' 4. Check for target/arch conflicts, e.g. dos and non-x86
 2321     if( (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS) and _
 2322         (fbGetCpuFamily( ) <> FB_CPUFAMILY_X86) ) then
 2323         errReportEx( FB_ERRMSG_DOSWITHNONX86, fbGetFbcArch( ), -1 )
 2324         fbcEnd( 1 )
 2325     end if
 2326 
 2327     '' 5. Select default backend based on selected arch, e.g. when compiling
 2328     ''    for x86-64 or ARM, we shouldn't default to -gen gas anymore (as
 2329     ''    long as it doesn't support it).
 2330     ''
 2331     '' This should be done no matter whether compiling for the native system
 2332     '' or cross-compiling. Even on a 64bit x86_64 host where
 2333     '' FB_DEFAULT_BACKEND is -gen gcc, we still prefer using -gen gas when
 2334     '' cross-compiling to 32bit x86.
 2335     if( fbGetCpuFamily( ) = FB_CPUFAMILY_X86 ) then
 2336         fbSetOption( FB_COMPOPT_BACKEND, FB_BACKEND_GAS )
 2337     else
 2338         fbSetOption( FB_COMPOPT_BACKEND, FB_BACKEND_GCC )
 2339     end if
 2340 
 2341     '' 6. -gen overrides any other backend setting.
 2342     if( fbc.backend >= 0 ) then
 2343         fbSetOption( FB_COMPOPT_BACKEND, fbc.backend )
 2344     end if
 2345 
 2346     '' 7. Check whether backend supports the target/arch.
 2347     '' -gen gas with non-x86 arch isn't possible.
 2348     if( (fbGetOption( FB_COMPOPT_BACKEND ) = FB_BACKEND_GAS) and _
 2349         (fbGetCpuFamily( ) <> FB_CPUFAMILY_X86) ) then
 2350         errReportEx( FB_ERRMSG_GENGASWITHNONX86, fbGetFbcArch( ), -1 )
 2351         fbcEnd( 1 )
 2352     end if
 2353 
 2354     '' Resource scripts are only allowed for win32 & co,
 2355     select case as const (fbGetOption(FB_COMPOPT_TARGET))
 2356     case FB_COMPTARGET_WIN32, FB_COMPTARGET_CYGWIN, FB_COMPTARGET_XBOX
 2357 
 2358     case else
 2359         dim as FBCIOFILE ptr rc = listGetHead(@fbc.rcs)
 2360         if (rc) then
 2361             errReportEx(FB_ERRMSG_RCFILEWRONGTARGET, rc->srcfile, -1)
 2362             fbcEnd(1)
 2363         end if
 2364     end select
 2365 
 2366     '' The embedded .xpm is only useful for the X11 gfxlib
 2367     select case as const (fbGetOption(FB_COMPOPT_TARGET))
 2368     case FB_COMPTARGET_LINUX, FB_COMPTARGET_DARWIN, _
 2369          FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _
 2370          FB_COMPTARGET_NETBSD
 2371 
 2372     case else
 2373         if (len(fbc.xpm.srcfile) > 0) then
 2374             errReportEx(FB_ERRMSG_RCFILEWRONGTARGET, fbc.xpm.srcfile, -1)
 2375             fbcEnd(1)
 2376         end if
 2377     end select
 2378 
 2379     if( fbc.asmsyntax >= 0 ) then
 2380         '' -asm only applies to x86 and x86_64
 2381         select case( fbGetCpuFamily( ) )
 2382         case FB_CPUFAMILY_X86, FB_CPUFAMILY_X86_64
 2383         case else
 2384             errReportEx( FB_ERRMSG_ASMOPTIONGIVENFORNONX86, fbGetTargetId( ), -1 )
 2385         end select
 2386 
 2387         '' -gen gas only supports -asm intel
 2388         if( (fbGetOption( FB_COMPOPT_BACKEND ) = FB_BACKEND_GAS) and _
 2389             (fbc.asmsyntax <> FB_ASMSYNTAX_INTEL) ) then
 2390             errReportEx( FB_ERRMSG_GENGASWITHOUTINTEL, "", -1 )
 2391         end if
 2392 
 2393         '' -asm overrides the target's default
 2394         fbSetOption( FB_COMPOPT_ASMSYNTAX, fbc.asmsyntax )
 2395     end if
 2396 
 2397     '' Enable -pic automatically when building a shared library on non-x86 Unixes
 2398     if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
 2399         if( hTargetNeedsPIC( ) ) then
 2400             fbSetOption( FB_COMPOPT_PIC, TRUE )
 2401         end if
 2402     end if
 2403 
 2404     '' Complain if -pic was given in cases where it's not needed/supported
 2405     if( fbGetOption( FB_COMPOPT_PIC ) ) then
 2406         if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_EXECUTABLE ) then
 2407             errReportEx( FB_ERRMSG_PICNOTSUPPORTEDFOREXE, "", -1 )
 2408         elseif( hTargetNeedsPIC( ) = FALSE ) then
 2409             errReportEx( FB_ERRMSG_PICNOTSUPPORTEDFORTARGET, "", -1 )
 2410         end if
 2411     end if
 2412 
 2413     '' TODO: Check whether subsystem/stacksize/xboxtitle were set and
 2414     '' complain about it when the target doesn't allow it, or just
 2415     '' ignore silently (that might not even be too bad for portability)?
 2416 end sub
 2417 
 2418 '' Determine base/prefix path
 2419 private sub fbcDeterminePrefix( )
 2420     '' Not already set from -prefix command line option?
 2421     if( len( fbc.prefix ) = 0 ) then
 2422         '' Then default to exepath() or the hard-coded prefix
 2423         #ifdef ENABLE_PREFIX
 2424             fbc.prefix = ENABLE_PREFIX + FB_HOST_PATHDIV
 2425         #else
 2426             fbc.prefix = pathStripDiv( exepath( ) ) + FB_HOST_PATHDIV
 2427             #ifndef ENABLE_STANDALONE
 2428                 '' Non-standalone fbc is in prefix/bin,
 2429                 '' just add '..' to get to prefix
 2430                 fbc.prefix += ".." + FB_HOST_PATHDIV
 2431             #endif
 2432         #endif
 2433     else
 2434         fbc.prefix += FB_HOST_PATHDIV
 2435     end if
 2436 end sub
 2437 
 2438 private sub fbcSetupCompilerPaths( )
 2439     ''
 2440     '' Standalone (classic FB):
 2441     ''
 2442     ''    bin/os[-arch]/
 2443     ''    inc/
 2444     ''    lib/os[-arch]/
 2445     ''
 2446     '' Normal (unix-style):
 2447     ''
 2448     ''    bin/[target-]
 2449     ''    include/freebasic[suffix]/
 2450     ''    lib/freebasic[suffix]/{target | os[-arch]}/
 2451     ''
 2452     '' x86 standalone traditionally uses the win32/dos/linux subdirs in bin/
 2453     '' and lib/, named after the target OS. For other architectures, the
 2454     '' arch name needs to be added to distinguish the subdir from the x86
 2455     '' version. (especially for cross-compiling)
 2456     ''
 2457     '' Normal has additional support for gcc targets (e.g. i686-pc-mingw32),
 2458     '' which have to be prefixed to the executable names of cross-compiling
 2459     '' tools in the bin/ directory (e.g. bin/i686-pc-mingw32-ld). However,
 2460     '' for native compilation, no target is prefixed to bin/ tools at all.
 2461     ''
 2462     '' Normal uses include/freebasic/ and lib/freebasic/ to hold FB includes
 2463     '' and libraries, to stay out of the way of the C ones in include/ and
 2464     '' lib/ and to conform to Linux distro packaging standards.
 2465     ''
 2466     '' With ENABLE_LIB64, we put 64bit libs into
 2467     ''    lib64/freebasic/<target>/
 2468     '' instead of the default
 2469     ''    lib/freebasic/<target>/
 2470     '' lib/ is then used for 32bit libs only. This is useful for some Linux
 2471     '' distros which use lib/ and lib64/ this way.
 2472     ''
 2473     '' - The paths are not terminated with [back]slashes here,
 2474     ''   except for the bin/ path. fbcFindBin() expects to only have to
 2475     ''   append the file name, for example:
 2476     ''     "prefix/bin/win32/" + "as.exe"
 2477     ''     "prefix/bin/" + "ld"
 2478     ''     "prefix/bin/i686-w64-mingw32-" + "ld"
 2479     ''
 2480 
 2481     dim as string targetid = fbGetTargetId( )
 2482 
 2483 #ifdef ENABLE_STANDALONE
 2484     '' Use default target name
 2485     fbc.binpath = fbc.prefix + "bin" + FB_HOST_PATHDIV + targetid + FB_HOST_PATHDIV
 2486     fbc.incpath = fbc.prefix + "inc"
 2487     fbc.libpath = fbc.prefix + "lib" + FB_HOST_PATHDIV + targetid
 2488 #else
 2489     dim as string fbname
 2490     #ifdef __FB_DOS__
 2491         '' Our subdirectory in include/ and lib/ is usually called
 2492         '' freebasic/, but on DOS that's too long... of course almost
 2493         '' no targetid or suffix can be used either.
 2494         fbname = "freebas"
 2495     #else
 2496         fbname = "freebasic"
 2497     #endif
 2498     #ifdef ENABLE_SUFFIX
 2499         fbname += ENABLE_SUFFIX
 2500     #endif
 2501 
 2502     dim libdirname as string = "lib"
 2503     #ifdef ENABLE_LIB64
 2504         if( fbIs64Bit( ) ) then
 2505             libdirname = "lib64"
 2506         end if
 2507     #endif
 2508 
 2509     fbc.binpath = fbc.prefix + "bin"     + FB_HOST_PATHDIV + fbc.targetprefix
 2510     fbc.incpath = fbc.prefix + "include" + FB_HOST_PATHDIV + fbname
 2511     fbc.libpath = fbc.prefix + libdirname + FB_HOST_PATHDIV + fbname + FB_HOST_PATHDIV + targetid
 2512 #endif
 2513 end sub
 2514 
 2515 private sub fbcPrintTargetInfo( )
 2516     var s = fbGetTargetId( )
 2517     s += ", " + *fbGetFbcArch( )
 2518     s += ", " & fbGetBits( ) & "bit"
 2519     #ifndef ENABLE_STANDALONE
 2520         if( len( fbc.target ) > 0 ) then
 2521             s += " (" + fbc.target + ")"
 2522         end if
 2523     #endif
 2524     print "target:", s
 2525 end sub
 2526 
 2527 private sub fbcDetermineMainName( )
 2528     '' Determine the main module path/name if not given via -m
 2529     if (len(fbc.mainname) = 0) then
 2530         '' 1) First input .bas module
 2531         dim as FBCIOFILE ptr m = listGetHead( @fbc.modules )
 2532         if( m ) then
 2533             fbc.mainname = m->srcfile
 2534         else
 2535             '' 2) First input .o
 2536             dim as string ptr objf = listGetHead( @fbc.objlist )
 2537             if( objf <> NULL ) then
 2538                 fbc.mainname = *objf
 2539             else
 2540                 '' 3) Neither input .bas nor .o, that is rare,
 2541                 '' but happens in this case:
 2542                 ''      $ fbc a.bas -lib -m a
 2543                 ''      $ fbc b.bas -lib
 2544                 ''      $ fbc -l a -l b
 2545                 '' Usually -x is used too though, so this
 2546                 '' fallback name won't be seen often.
 2547                 '' This name should be 8.3 compatible (for DOS)
 2548                 fbc.mainname = "unnamed"
 2549             end if
 2550         end if
 2551         fbc.mainname = hStripExt(fbc.mainname)
 2552     end if
 2553 end sub
 2554 
 2555 '' Build the intermediate file name for the given module and step
 2556 private function hGetAsmName _
 2557     ( _
 2558         byval module as FBCIOFILE ptr, _
 2559         byval stage as integer _
 2560     ) as string
 2561 
 2562     dim as zstring ptr ext = any
 2563     dim as string asmfile
 2564 
 2565     '' Based on the objfile name so it's also affected by -o
 2566     asmfile = hStripExt( *module->objfile )
 2567 
 2568     ext = @".asm"
 2569 
 2570     if( stage = 1 ) then
 2571         select case( fbGetOption( FB_COMPOPT_BACKEND ) )
 2572         case FB_BACKEND_GCC
 2573             ext = @".c"
 2574         case FB_BACKEND_LLVM
 2575             ext = @".ll"
 2576         end select
 2577     end if
 2578 
 2579     asmfile += *ext
 2580 
 2581     function = asmfile
 2582 end function
 2583 
 2584 private sub hCompileBas _
 2585     ( _
 2586         byval module as FBCIOFILE ptr, _
 2587         byval is_main as integer, _
 2588         byval is_fbctinf as integer _
 2589     )
 2590 
 2591     dim as integer prevlang = any, prevouttype = any, restarts = any
 2592     dim as string asmfile, pponlyfile
 2593 
 2594     asmfile = hGetAsmName( module, 1 )
 2595 
 2596     '' Clean up stage 1 output (FB backend's output, *.asm/*.c/*.ll),
 2597     '' unless -R was given, and additionally in case of -gen gas, unless -RR
 2598     '' was given (because for -gen gas, the FB backend's .asm output is also
 2599     '' the final .asm which -RR is supposed to preserve).
 2600     if( (not fbc.keepasm) and _
 2601         ((fbGetOption( FB_COMPOPT_BACKEND ) <> FB_BACKEND_GAS) or _
 2602          (not fbc.keepfinalasm)) ) then
 2603         fbcAddTemp( asmfile )
 2604     end if
 2605 
 2606     '' -pp?
 2607     if( fbGetOption( FB_COMPOPT_PPONLY ) ) then
 2608         '' Re-use the full -o path/filename for the -pp output file,
 2609         '' since no .o will be generated anyways (if -o was given)
 2610         pponlyfile = *module->objfile
 2611         if( module->is_custom_objfile = FALSE ) then
 2612             '' Otherwise, use a default file name
 2613             pponlyfile = hStripExt( pponlyfile ) + ".pp.bas"
 2614         end if
 2615     end if
 2616 
 2617     if( fbc.verbose ) then
 2618         print "compiling: ", module->srcfile; " -o "; asmfile;
 2619         if( fbGetOption( FB_COMPOPT_PPONLY ) ) then
 2620             print " -pp " + pponlyfile;
 2621         end if
 2622         if( is_main ) then
 2623             print " (main module)";
 2624         elseif( is_fbctinf ) then
 2625             print " (FB compile-time info)";
 2626         end if
 2627         print
 2628     end if
 2629 
 2630     restarts = 0
 2631     '' preserve orginal values that might have to restored
 2632     '' (e.g. -lang mode could be overwritten while parsing due to #lang,
 2633     '' but that shouldn't affect other modules)
 2634     prevlang = fbGetOption( FB_COMPOPT_LANG )
 2635     prevouttype = fbGetOption( FB_COMPOPT_OUTTYPE )
 2636 
 2637     if( is_fbctinf ) then
 2638         '' Switch to -c mode temporarily to get the compiler to write objinfo
 2639         fbSetOption( FB_COMPOPT_OUTTYPE, FB_OUTTYPE_OBJECT )
 2640     end if
 2641 
 2642     do
 2643         '' init the parser
 2644         fbInit( is_main, restarts )
 2645 
 2646         if( is_fbctinf ) then
 2647             '' Let the compiler know about all libs collected so far,
 2648             '' so the fbctinf module represents all the other modules
 2649             '' compiled/included in this fbc invocation.
 2650             fbSetLibs( @fbc.finallibs, @fbc.finallibpaths )
 2651         else
 2652             '' Add only the libs and paths passed on the command line,
 2653             '' so this module will only include objinfo for those libs
 2654             '' and the ones found while parsing it, but not unrelated
 2655             '' libs from other modules.
 2656             fbSetLibs( @fbc.libs, @fbc.libpaths )
 2657         end if
 2658 
 2659         fbCompile( module->srcfile, asmfile, pponlyfile, is_main )
 2660 
 2661         '' If there were any errors during parsing, just exit without
 2662         '' doing anything else.
 2663         if( errGetCount( ) > 0 ) then
 2664             fbcEnd( 1 )
 2665         end if
 2666 
 2667         '' Don't restart unless asked for
 2668         if( fbShouldRestart( ) = FALSE ) then
 2669             exit do
 2670         end if
 2671 
 2672         '' Restart
 2673         restarts += 1
 2674 
 2675         '' Shutdown the parser before restarting
 2676         fbEnd( )
 2677     loop
 2678 
 2679     '' (unnecessary for the empty fbctinf module, it won't add anything new)
 2680     if( is_fbctinf = FALSE ) then
 2681         '' Update the list of libs and paths with the ones found when parsing
 2682         fbGetLibs( @fbc.finallibs, @fbc.finallibpaths )
 2683     end if
 2684 
 2685     '' Shutdown the parser
 2686     fbEnd( )
 2687 
 2688     '' Restore original options
 2689     fbSetOption( FB_COMPOPT_OUTTYPE, prevouttype )
 2690     fbSetOption( FB_COMPOPT_LANG, prevlang )
 2691 end sub
 2692 
 2693 private sub hCompileModules( )
 2694     dim as integer ismain = any, checkmain = any
 2695     dim as string mainfile
 2696     dim as FBCIOFILE ptr module = any
 2697 
 2698     ismain = FALSE
 2699 
 2700     select case fbGetOption( FB_COMPOPT_OUTTYPE )
 2701     case FB_OUTTYPE_EXECUTABLE, FB_OUTTYPE_DYNAMICLIB
 2702         checkmain = TRUE
 2703     case else
 2704         '' When building an object or a library (-c/-r, -lib), nothing
 2705         '' is compiled with ismain = TRUE until -m was given for it.
 2706         '' This makes sense because -c is usually used to compile
 2707         '' single modules of which only a very specific one is the
 2708         '' main one (nobody would want -c to include main() everywhere),
 2709         '' and because -lib is for making libraries which generally
 2710         '' don't include a main module for programs to use.
 2711         checkmain = fbc.mainset
 2712     end select
 2713 
 2714     if( checkmain ) then
 2715         '' Note: This causes the path given with -m to be ignored in
 2716         '' the ismain check below. This is good because -m is easier
 2717         '' to use that way (e.g. fbc ../../main.bas -m main), and bad
 2718         '' because then modules with the same name but in different
 2719         '' directories will both be seen as the main one.
 2720         mainfile = hStripPath( fbc.mainname )
 2721     end if
 2722 
 2723     module = listGetHead( @fbc.modules )
 2724 
 2725     if( module = NULL ) then
 2726         '' No input .bas files to compile - make sure to add the libs
 2727         '' from the command line to the final lists anyways.
 2728         strsetCopy( @fbc.finallibs, @fbc.libs )
 2729         strsetCopy( @fbc.finallibpaths, @fbc.libpaths )
 2730         exit sub
 2731     end if
 2732 
 2733     '' We have input .bas files to compile - hCompileBas() will take care of
 2734     '' copying the command line libs into the final lists:
 2735     '' 1. into the compiler
 2736     ''    (fbc.libs -> fbSetLibs() -> compiler)
 2737     '' 2. compiler collects additional #inclibs etc...
 2738     '' 3. and copy back into final lists
 2739     ''    (compiler -> fbGetLibs() -> fbc.finallibs)
 2740 
 2741     do
 2742         if( checkmain ) then
 2743             ismain = (mainfile = hStripPath( hStripExt( module->srcfile ) ))
 2744             '' Note: checking continues for all modules, because
 2745             '' "the" main module could be passed multiple times,
 2746             '' and it makes sense to always treat it the same,
 2747             '' so that <fbc 1.bas 1.bas -c> generates the same 1.o
 2748             '' twice and <fbc 1.bas 1.bas> causes a duplicated
 2749             '' definition of main().
 2750             /'checkmain = not ismain'/
 2751         end if
 2752 
 2753         hCompileBas( module, ismain, FALSE )
 2754 
 2755         module = listGetNext( module )
 2756     loop while( module )
 2757 end sub
 2758 
 2759 private function hParseXpm _
 2760     ( _
 2761         byref xpmfile as string, _
 2762         byref code as string _
 2763     ) as integer
 2764 
 2765     code += !"\ndim shared as zstring ptr "
 2766     code += "fb_program_icon_data"
 2767     code += !"(0 to ...) = _\n{ _\n"
 2768 
 2769     dim as integer f = freefile( )
 2770     if( open( xpmfile, for input, as #f ) ) then
 2771         exit function
 2772     end if
 2773 
 2774     dim as string ln
 2775 
 2776     '' Check for the header line
 2777     line input #f, ln
 2778     if( ucase( ln ) <> "/* XPM */" ) then
 2779         '' Invalid XPM header
 2780         close #f
 2781         exit function
 2782     end if
 2783 
 2784     '' Check for lines containing strings (color and pixel lines)
 2785     '' Other lines (declaration line, empty lines, C comments, ...) aren't
 2786     '' explicitely handled, but should automatically be ignored, as long as
 2787     '' they don't contain strings.
 2788     dim as integer saw_rows = FALSE
 2789     while( eof( f ) = FALSE )
 2790         line input #f, ln
 2791 
 2792         '' Strip everything in front of the first '"'
 2793         ln = right( ln, len( ln ) - (instr( ln, """" ) - 1) )
 2794 
 2795         '' Strip everything behind the second '"'
 2796         ln = left( ln, instr( 2, ln, """" ) )
 2797 
 2798         '' Got something left?
 2799         if( len( ln ) > 0 ) then
 2800             '' Add an entry to the array, in a new line,
 2801             '' separated by a comma, if it's not the first one.
 2802             if( saw_rows ) then
 2803                 code += !", _\n"
 2804             end if
 2805             code += !"\t@" + ln
 2806             saw_rows = TRUE
 2807         end if
 2808     wend
 2809 
 2810     close #f
 2811 
 2812     if( saw_rows = FALSE ) then
 2813         '' No image data found
 2814         exit function
 2815     end if
 2816 
 2817     '' Line break after the last entry
 2818     code += !" _ \n"
 2819 
 2820     code += !"}\n\n"
 2821 
 2822     '' Symbol for the gfxlib
 2823     code += !"extern as zstring ptr ptr fb_program_icon alias ""fb_program_icon""\n"
 2824     code += "dim shared as zstring ptr ptr fb_program_icon = " & _
 2825                     !"@fb_program_icon_data(0)\n"
 2826 
 2827     function = TRUE
 2828 end function
 2829 
 2830 '' Turns the .xpm icon resource into a .bas file,
 2831 '' then compiles that using the normal FB compilation process.
 2832 private function hCompileXpm( ) as integer
 2833     dim as string xpmfile, code
 2834     dim as integer fo = any
 2835 
 2836     if( len( fbc.xpm.srcfile ) = 0 ) then
 2837         return TRUE
 2838     end if
 2839 
 2840     '' Remember *.xpm file name
 2841     xpmfile = fbc.xpm.srcfile
 2842 
 2843     '' Set *.bas name based on input file name or -o <file>:
 2844     if( len( *fbc.xpm.objfile ) > 0 ) then
 2845         fbc.xpm.srcfile = hStripExt( *fbc.xpm.objfile )
 2846     end if
 2847 
 2848     '' foo.xpm -> foo.xpm.bas to avoid collision with foo.bas
 2849     fbc.xpm.srcfile &= ".bas"
 2850 
 2851     if( fbc.verbose ) then
 2852         print "parsing xpm: ", xpmfile & " -o " & fbc.xpm.srcfile
 2853     end if
 2854 
 2855     if( hParseXpm( xpmfile, code ) = FALSE ) then
 2856         '' TODO: show error message
 2857         exit function
 2858     end if
 2859 
 2860     fo = freefile( )
 2861     if( open( fbc.xpm.srcfile, for output, as #fo ) ) then
 2862         '' TODO: show error message
 2863         exit function
 2864     end if
 2865     print #fo, code;
 2866     close #fo
 2867 
 2868     '' Clean up the temp .bas if -R wasn't given
 2869     if( fbc.keepasm = FALSE ) then
 2870         fbcAddTemp( fbc.xpm.srcfile )
 2871     end if
 2872 
 2873     hCompileBas( @fbc.xpm, FALSE, FALSE )
 2874     function = TRUE
 2875 end function
 2876 
 2877 private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as integer
 2878     dim as string ln, asmfile
 2879 
 2880     asmfile = hGetAsmName( module, 2 )
 2881     '' Clean up stage 2 output (the final .asm for -gen gcc/llvm) unless
 2882     '' -RR was given.
 2883     if( fbc.keepfinalasm = FALSE ) then
 2884         fbcAddTemp( asmfile )
 2885     end if
 2886 
 2887     select case( fbGetOption( FB_COMPOPT_BACKEND ) )
 2888     case FB_BACKEND_GCC
 2889         select case( fbGetCpuFamily( ) )
 2890         case FB_CPUFAMILY_X86
 2891             ln += "-m32 "
 2892         case FB_CPUFAMILY_X86_64
 2893             ln += "-m64 "
 2894         end select
 2895 
 2896         if( fbc.cputype_is_native ) then
 2897             ln += "-march=native "
 2898         else
 2899             ln += "-march=" + *fbGetGccArch( ) + " "
 2900         end if
 2901 
 2902         if( fbGetOption( FB_COMPOPT_PIC ) ) then
 2903             ln += "-fPIC "
 2904         end if
 2905 
 2906         ln += "-S -nostdlib -nostdinc -Wall -Wno-unused-label " + _
 2907               "-Wno-unused-function -Wno-unused-variable " + _
 2908               "-Wno-unused-but-set-variable "
 2909 
 2910         '' Don't warn about non-standard main() signature
 2911         '' (we emit "ubyte **argv" instead of "char **argv")
 2912         ln += "-Wno-main "
 2913 
 2914         '' helps finding ir-hlc bugs
 2915         ln += "-Werror-implicit-function-declaration "
 2916 
 2917         ln += "-O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + " "
 2918 
 2919         '' Do not let gcc make assumptions about pointers; FB isn't strict about it.
 2920         ln += "-fno-strict-aliasing "
 2921 
 2922         '' The rtlib sets its own rounding mode, don't let gcc make assumptions.
 2923         ln += "-frounding-math "
 2924 
 2925         '' ?
 2926         ln += "-fno-math-errno "
 2927 
 2928         '' Note: we shouldn't use some options like e.g. -ffast-math, because
 2929         '' they cause incompatibilities with the ASM backend. For example:
 2930         ''    dim as double d = INF
 2931         ''    print d - d
 2932         '' prints -NaN (IND) under the ASM backend because the FPU does the
 2933         '' subtraction, however with the C backend with, gcc -ffast-math
 2934         '' optimizes out the subtraction (even under -O0) and inserts 0 instead.
 2935 
 2936         '' Define signed integer overflow
 2937         ln += "-fwrapv "
 2938 
 2939         '' Avoid gcc exception handling bloat
 2940         ln += "-fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables "
 2941 
 2942         '' Prevent format string errors on gcc 9.x. (enabled by default with '-Wall')
 2943         '' TODO: fbc currently emits the ZSTRING type as 'uint8' when it
 2944         '' should probably preserve the 'char' type.  In C, there are 3 
 2945         '' distinct types, 'char', 'unsigned char', 'signed char'.
 2946         '' See ir-hlc.bas:hEmitType()
 2947         ln += "-Wno-format "
 2948 
 2949         if( fbGetOption( FB_COMPOPT_DEBUGINFO ) ) then
 2950             ln += "-g "
 2951         end if
 2952 
 2953         if( fbGetOption( FB_COMPOPT_FPUTYPE ) = FB_FPUTYPE_SSE ) then
 2954             ln += "-mfpmath=sse -msse2 "
 2955         end if
 2956 
 2957         select case( fbGetCpuFamily( ) )
 2958         case FB_CPUFAMILY_X86, FB_CPUFAMILY_X86_64
 2959             if( fbGetOption( FB_COMPOPT_ASMSYNTAX ) = FB_ASMSYNTAX_INTEL ) then
 2960                 ln += "-masm=intel "
 2961             end if
 2962         end select
 2963 
 2964     case FB_BACKEND_LLVM
 2965         select case( fbGetCpuFamily( ) )
 2966         case FB_CPUFAMILY_X86
 2967             ln += "-march=x86 "
 2968         case FB_CPUFAMILY_X86_64
 2969             ln += "-march=x86-64 "
 2970         case FB_CPUFAMILY_ARM
 2971             ln += "-march=arm "
 2972         case FB_CPUFAMILY_AARCH64
 2973             '' From the GCC manual:
 2974             '' -march=name
 2975             '' Specify the name of the target architecture and, 
 2976             '' optionally, one or more feature modifiers. This option 
 2977             '' has the form -march=arch{+[no]feature}*.
 2978             '' 
 2979             '' The permissible values for arch are 
 2980             '' 'armv8-a'
 2981             '' 'armv8.1-a' = 'armv8-a' + ARMv8.1-A 
 2982             '' 'armv8.2-a' = 'armv8.1-a' + ARMv8.2-A
 2983             '' 'armv8.3-a' = 'armv8.2-a' + ARMv8.3-A
 2984             '' 'armv8.4-a' = 'armv8.3-a' + ARMv8.4-A
 2985             '' 'armv8.5-a' = 'armv8.4-a' + ARMv8.5-A
 2986             '' 'native' = architecture of the host system
 2987             '' 
 2988             '' It enables the '+crc', '+lse', and '+rdma' features.
 2989             '' 
 2990             '' The value 'native' is available on native AArch64 
 2991             '' GNU/Linux and causes the compiler to pick the 
 2992             '' architecture of the host system. This option has no 
 2993             '' effect if the compiler is unable to recognize the 
 2994             '' architecture of the host system, The permissible 
 2995             '' values for feature are listed in the sub-section on 
 2996             '' ['-march' and '-mcpu' Feature Modifiers]. Where 
 2997             '' conflicting feature modifiers are specified, the 
 2998             '' right-most feature is used. GCC uses name to determine 
 2999             '' what kind of instructions it can emit when generating 
 3000             '' assembly code. If '-march' is specified without either 
 3001             '' of '-mtune' or '-mcpu' also being specified, the code
 3002             '' is tuned to perform well across a range of target 
 3003             '' processors implementing the target architecture.
 3004 
 3005             ln += "-march=armv8-a "
 3006         end select
 3007 
 3008         if( fbGetOption( FB_COMPOPT_PIC ) ) then
 3009             ln += "-relocation-model=pic "
 3010         end if
 3011 
 3012         ln += "-O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + " "
 3013 
 3014         select case( fbGetCpuFamily( ) )
 3015         case FB_CPUFAMILY_X86, FB_CPUFAMILY_X86_64
 3016             if( fbGetOption( FB_COMPOPT_ASMSYNTAX ) = FB_ASMSYNTAX_INTEL ) then
 3017                 ln += "--x86-asm-syntax=intel "
 3018             end if
 3019         end select
 3020 
 3021     end select
 3022 
 3023     ln += """" + hGetAsmName( module, 1 ) + """ "
 3024     ln += "-o """ + asmfile + """"
 3025     ln += fbc.extopt.gcc
 3026 
 3027     select case( fbGetOption( FB_COMPOPT_BACKEND ) )
 3028     case FB_BACKEND_GCC
 3029         function = fbcRunBin( "compiling C", FBCTOOL_GCC, ln )
 3030     case FB_BACKEND_LLVM
 3031         function = fbcRunBin( "compiling LLVM IR", FBCTOOL_LLC, ln )
 3032     end select
 3033 end function
 3034 
 3035 private sub hCompileStage2Modules( )
 3036     dim as FBCIOFILE ptr module = listGetHead( @fbc.modules )
 3037     while( module )
 3038         if( hCompileStage2Module( module ) = FALSE ) then
 3039             fbcEnd( 1 )
 3040         end if
 3041         module = listGetNext( module )
 3042     wend
 3043 end sub
 3044 
 3045 private function hAssembleModule( byval module as FBCIOFILE ptr ) as integer
 3046     dim as string ln
 3047 
 3048     select case( fbGetCpuFamily( ) )
 3049     case FB_CPUFAMILY_X86
 3050         if (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN) then
 3051             ln += "-arch i386 "
 3052         else
 3053             ln += "--32 "
 3054         endif
 3055     case FB_CPUFAMILY_X86_64
 3056         if (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN) then
 3057             ln += "-arch x86_64 "
 3058         else
 3059             ln += "--64 "
 3060         endif
 3061     end select
 3062 
 3063     if( fbGetOption( FB_COMPOPT_DEBUGINFO ) = FALSE ) then
 3064         if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then
 3065             ln += "--strip-local-absolute "
 3066         endif
 3067     end if
 3068     ln += """" + hGetAsmName( module, 2 ) + """ "
 3069     ln += "-o """ + *module->objfile + """"
 3070     ln += fbc.extopt.gas
 3071 
 3072     if( fbcRunBin( "assembling", FBCTOOL_AS, ln ) = FALSE ) then
 3073         exit function
 3074     end if
 3075 
 3076     '' Clean up the .o if -C wasn't given
 3077     if( fbc.keepobj = FALSE ) then
 3078         fbcAddTemp( *module->objfile )
 3079     end if
 3080 
 3081     function = TRUE
 3082 end function
 3083 
 3084 private sub hAssembleModules( )
 3085     dim as FBCIOFILE ptr module = listGetHead( @fbc.modules )
 3086     while( module )
 3087         if( hAssembleModule( module ) = FALSE ) then
 3088             fbcEnd( 1 )
 3089         end if
 3090         module = listGetNext( module )
 3091     wend
 3092 end sub
 3093 
 3094 private function hAssembleRc( byval rc as FBCIOFILE ptr ) as integer
 3095 #ifdef ENABLE_GORC
 3096     '' Using GoRC for the classical native win32 standalone build
 3097     '' Note: GoRC /fo doesn't accept anything except *.obj, not even *.o,
 3098     '' so we need to make it *.obj and then rename it afterwards.
 3099 
 3100     dim as integer need_rename = FALSE
 3101 
 3102     '' Ensure to use *.obj so GoRC accepts it
 3103     if( hGetFileExt( *rc->objfile ) <> "obj" ) then
 3104         need_rename = TRUE
 3105         *rc->objfile += ".obj"
 3106     end if
 3107 
 3108     '' Change the include env var to point to the (hopefully present)
 3109     '' win/rc/*.h headers.
 3110     dim as string oldinclude = trim( environ( "INCLUDE" ) )
 3111     setenviron "INCLUDE=" + fbc.incpath + _
 3112                (FB_HOST_PATHDIV + "win" + FB_HOST_PATHDIV + "rc")
 3113 
 3114     dim as string ln = "/ni /nw /o "
 3115 
 3116     if( fbGetCpuFamily( ) = FB_CPUFAMILY_X86_64 ) then
 3117         ln += "/machine X64 "
 3118     end if
 3119 
 3120     ln &= "/fo """ & *rc->objfile & """"
 3121     ln &= " """ & rc->srcfile & """"
 3122 
 3123     if( fbcRunBin( "compiling rc", FBCTOOL_GORC, ln ) = FALSE ) then
 3124         exit function
 3125     end if
 3126 
 3127     '' restore the include env var
 3128     if( len( oldinclude ) > 0 ) then
 3129         setenviron "INCLUDE=" + oldinclude
 3130     end if
 3131 
 3132     if( need_rename ) then
 3133         dim as string badname = *rc->objfile
 3134         *rc->objfile = hStripExt( *rc->objfile )
 3135         '' Rename back so it will be found by ld/the user
 3136         function = (name( badname, *rc->objfile ) = 0)
 3137     else
 3138         function = TRUE
 3139     end if
 3140 #else
 3141     '' Using binutils' windres for all other setups (e.g. cross-compiling
 3142     '' linux -> win32)
 3143     '' Note: windres uses gcc -E to preprocess the .rc by default,
 3144     '' that may not be 100% compatible to GoRC.
 3145 
 3146     dim as string ln = "--output-format=coff --include-dir=."
 3147     ln += " """ + rc->srcfile + """"
 3148     ln += " """ + *rc->objfile + """"
 3149 
 3150     function = fbcRunBin( "compiling rc", FBCTOOL_WINDRES, ln )
 3151 #endif
 3152 
 3153     '' Clean up the .o if -C wasn't given
 3154     if( fbc.keepobj = FALSE ) then
 3155         fbcAddTemp( *rc->objfile )
 3156     end if
 3157 end function
 3158 
 3159 private sub hAssembleRcs( )
 3160     '' Compile .rc/.res files
 3161     dim as FBCIOFILE ptr rc = listGetHead( @fbc.rcs )
 3162     while( rc )
 3163         if( hAssembleRc( rc ) = FALSE ) then
 3164             fbcEnd( 1 )
 3165         end if
 3166         rc = listGetNext( rc )
 3167     wend
 3168 end sub
 3169 
 3170 private sub hAssembleXpm( )
 3171     if( len( fbc.xpm.srcfile ) > 0 ) then
 3172         if( fbGetOption( FB_COMPOPT_BACKEND ) <> FB_BACKEND_GAS ) then
 3173             hCompileStage2Module( @fbc.xpm )
 3174         end if
 3175         if( hAssembleModule( @fbc.xpm ) = FALSE ) then
 3176             fbcEnd( 1 )
 3177         end if
 3178     end if
 3179 end sub
 3180 
 3181 private function hCompileFbctinf( ) as integer
 3182     dim as FBCIOFILE fbctinf
 3183     dim as string objfile
 3184     dim as integer fo = any
 3185 
 3186     '' Compile an empty .bas into the fbctinf object file
 3187     '' (it will contain only objinfo)
 3188     fbctinf.srcfile = FB_INFOSEC_BASNAME
 3189     objfile = FB_INFOSEC_OBJNAME
 3190     fbctinf.objfile = @objfile
 3191 
 3192     if( fbc.verbose ) then
 3193         print "creating: ", fbctinf.srcfile
 3194     end if
 3195 
 3196     '' Create the empty .bas file
 3197     fo = freefile( )
 3198     if( open( fbctinf.srcfile, for output, as #fo ) ) then
 3199         exit function
 3200     end if
 3201     close #fo
 3202 
 3203     '' Clean up the temp .bas if -R wasn't given
 3204     if( fbc.keepasm = FALSE ) then
 3205         fbcAddTemp( fbctinf.srcfile )
 3206     end if
 3207 
 3208     hCompileBas( @fbctinf, FALSE, TRUE )
 3209     if( fbGetOption( FB_COMPOPT_BACKEND ) <> FB_BACKEND_GAS ) then
 3210         hCompileStage2Module( @fbctinf )
 3211     end if
 3212     function = hAssembleModule( @fbctinf )
 3213 end function
 3214 
 3215 private function hArchiveFiles( ) as integer
 3216     hSetOutName( )
 3217 
 3218     '' Remove lib*.a if it already exists, because ar doesn't overwrite
 3219     safeKill( fbc.outname )
 3220 
 3221     dim as string ln = "-rsc " + QUOTE + fbc.outname + (QUOTE + " ")
 3222 
 3223     if( fbGetOption( FB_COMPOPT_OBJINFO ) and (not fbIsCrossComp( )) ) then
 3224         if( hCompileFbctinf( ) ) then
 3225             '' The objinfo reader expects the fbctinf object to be
 3226             '' the first object file in libraries, so it must be
 3227             '' specified first on the archiver command line:
 3228             ln += QUOTE + FB_INFOSEC_OBJNAME + QUOTE + " "
 3229         end if
 3230         fbcAddTemp( FB_INFOSEC_OBJNAME )
 3231     end if
 3232 
 3233     dim as string ptr objfile = listGetHead( @fbc.objlist )
 3234     while( objfile )
 3235         ln += """" + *objfile + """ "
 3236         objfile = listGetNext( objfile )
 3237     wend
 3238 
 3239     '' invoke ar
 3240     function = fbcRunBin( "archiving", FBCTOOL_AR, ln )
 3241 end function
 3242 
 3243 private sub hSetDefaultLibPaths( )
 3244     '' compiler's lib/
 3245     fbcAddDefLibPath( fbc.libpath )
 3246 
 3247     '' and the current path
 3248     fbcAddDefLibPath( "." )
 3249 
 3250 #ifndef ENABLE_STANDALONE
 3251     '' Add gcc's private lib directory, to find libgcc
 3252     '' This is for installing into Unix-like systems, and not for
 3253     '' standalone, which has libgcc in the main lib/.
 3254     fbcAddLibPathFor( "libgcc.a" )
 3255 
 3256     select case( fbGetOption( FB_COMPOPT_TARGET ) )
 3257     case FB_COMPTARGET_DOS
 3258         '' Help out the DJGPP linker to find DJGPP's lib/ dir.
 3259         '' It doesn't seem to add it by default like on other systems.
 3260         '' Note: Can't use libc here, we have a fixed copy of that in
 3261         '' the compiler's lib/ dir.
 3262         fbcAddLibPathFor( "libm.a" )
 3263     case FB_COMPTARGET_WIN32
 3264         '' Help the MinGW linker to find MinGW's lib/ dir, allowing
 3265         '' the C:\MinGW dir to be renamed and linking to still work.
 3266         fbcAddLibPathFor( "libmingw32.a" )
 3267     end select
 3268 #endif
 3269 end sub
 3270 
 3271 private sub fbcAddDefLib(byval libname as zstring ptr)
 3272     strsetAdd(@fbc.finallibs, *libname, TRUE)
 3273 end sub
 3274 
 3275 private function hGetFbLibNameSuffix( ) as string
 3276     dim s as string
 3277     if( fbGetOption( FB_COMPOPT_MULTITHREADED ) ) then
 3278         s += "mt"
 3279     end if
 3280     if( fbGetOption( FB_COMPOPT_PIC ) ) then
 3281         s += "pic"
 3282     end if
 3283     function = s
 3284 end function
 3285 
 3286 private sub hAddDefaultLibs( )
 3287     '' select the right FB rtlib
 3288     fbcAddDefLib( "fb" + hGetFbLibNameSuffix( ) )
 3289 
 3290     '' and the gfxlib, if gfx functions were used
 3291     if( fbGetOption( FB_COMPOPT_GFX ) ) then
 3292         fbcAddDefLib( "fbgfx" + hGetFbLibNameSuffix( ) )
 3293 
 3294         select case as const( fbGetOption( FB_COMPOPT_TARGET ) )
 3295         case FB_COMPTARGET_WIN32, FB_COMPTARGET_CYGWIN
 3296             fbcAddDefLib( "gdi32" )
 3297             fbcAddDefLib( "winmm" )
 3298 
 3299         case FB_COMPTARGET_LINUX, FB_COMPTARGET_FREEBSD, _
 3300              FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD, _
 3301              FB_COMPTARGET_DARWIN
 3302 
 3303             #if defined(__FB_LINUX__) or _
 3304                 defined(__FB_FREEBSD__) or _
 3305                 defined(__FB_OPENBSD__) or _
 3306                 defined(__FB_NETBSD__)
 3307                 fbcAddDefLibPath( "/usr/X11R6/lib" )
 3308             #endif
 3309 
 3310             #if defined(__FB_DARWIN__) and defined(ENABLE_XQUARTZ)
 3311                 fbcAddDefLibPAth( "/opt/X11/lib" )
 3312             #endif
 3313 
 3314             #if (not defined(__FB_DARWIN__)) or defined(ENABLE_XQUARTZ)
 3315                 fbcAddDefLib( "X11" )
 3316                 fbcAddDefLib( "Xext" )
 3317                 fbcAddDefLib( "Xpm" )
 3318                 fbcAddDefLib( "Xrandr" )
 3319                 fbcAddDefLib( "Xrender" )
 3320             #endif
 3321 
 3322         end select
 3323     end if
 3324 
 3325     select case as const fbGetOption( FB_COMPOPT_TARGET )
 3326     case FB_COMPTARGET_CYGWIN
 3327         fbcAddDefLib( "gcc" )
 3328         fbcAddDefLib( "cygwin" )
 3329         fbcAddDefLib( "kernel32" )
 3330         fbcAddDefLib( "user32" )
 3331 
 3332         '' profiling?
 3333         if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
 3334             fbcAddDefLib( "gmon" )
 3335         end if
 3336 
 3337     case FB_COMPTARGET_DARWIN
 3338         fbcAddDefLib( "gcc" )
 3339         fbcAddDefLib( "System" )
 3340         fbcAddDefLib( "pthread" )
 3341         fbcAddDefLib( "ncurses" )
 3342 
 3343     case FB_COMPTARGET_DOS
 3344         fbcAddDefLib( "gcc" )
 3345         fbcAddDefLib( "c" )
 3346         fbcAddDefLib( "m" )
 3347         if( fbGetOption( FB_COMPOPT_MULTITHREADED ) ) then
 3348             fbcAddDefLib( "pthread" )
 3349             fbcAddDefLib( "socket" )
 3350         end if
 3351 
 3352     case FB_COMPTARGET_FREEBSD
 3353         fbcAddDefLib( "gcc" )
 3354         fbcAddDefLib( "pthread" )
 3355         fbcAddDefLib( "c" )
 3356         fbcAddDefLib( "m" )
 3357         fbcAddDefLib( "ncurses" )
 3358 
 3359     case FB_COMPTARGET_LINUX
 3360         ''
 3361         '' Notes:
 3362         ''
 3363         '' When linking statically, -lpthread apparently should be
 3364         '' linked before -lc. Otherwise there can be errors due to
 3365         '' -lpthread/-lc containing overlapping symbols (but the pthread
 3366         '' ones should be used). This is confirmed by minimal testing,
 3367         '' searching the web and 'gcc -pthread' behavior.
 3368         ''
 3369         '' libncurses and libtinfo: FB's rtlib depends on the libtinfo
 3370         '' part of ncurses, which sometimes is included in libncurses
 3371         '' and sometimes separate (depending on how ncurses was built).
 3372 
 3373         '' Prefer libtinfo over libncurses
 3374         if( (len( fbcFindLibFile( "libtinfo.a"  ) ) > 0) or _
 3375             (len( fbcFindLibFile( "libtinfo.so" ) ) > 0) ) then
 3376             fbcAddDefLib( "tinfo" )
 3377         else
 3378             fbcAddDefLib( "ncurses" )
 3379         end if
 3380 
 3381         fbcAddDefLib( "m" )
 3382         fbcAddDefLib( "dl" )
 3383         fbcAddDefLib( "pthread" )
 3384         fbcAddDefLib( "gcc" )
 3385         '' Link libgcc_eh if it exists (it depends on the gcc build)
 3386         if( (len( fbcFindLibFile( "libgcc_eh.a"  ) ) > 0) or _
 3387             (len( fbcFindLibFile( "libgcc_eh.so" ) ) > 0) ) then
 3388             fbcAddDefLib( "gcc_eh" )
 3389         end if
 3390         fbcAddDefLib( "c" )
 3391 
 3392     case FB_COMPTARGET_NETBSD
 3393         '' TODO
 3394 
 3395     case FB_COMPTARGET_OPENBSD
 3396         fbcAddDefLib( "gcc" )
 3397         fbcAddDefLib( "pthread" )
 3398         fbcAddDefLib( "c" )
 3399         fbcAddDefLib( "m" )
 3400         fbcAddDefLib( "ncurses" )
 3401 
 3402     case FB_COMPTARGET_WIN32
 3403         fbcAddDefLib( "gcc" )
 3404         fbcAddDefLib( "msvcrt" )
 3405         fbcAddDefLib( "kernel32" )
 3406         fbcAddDefLib( "user32" )
 3407         fbcAddDefLib( "mingw32" )
 3408         fbcAddDefLib( "mingwex" )
 3409         fbcAddDefLib( "moldname" )
 3410 
 3411         '' Link libgcc_eh if it exists
 3412         if( (len( fbcFindLibFile( "libgcc_eh.a"     ) ) > 0) or _
 3413             (len( fbcFindLibFile( "libgcc_eh.dll.a" ) ) > 0) ) then
 3414             '' Needed by mingw.org toolchain, but not TDM-GCC
 3415             fbcAddDefLib( "gcc_eh" )
 3416         end if
 3417 
 3418         '' profiling?
 3419         if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
 3420             fbcAddDefLib( "gmon" )
 3421         end if
 3422 
 3423     case FB_COMPTARGET_XBOX
 3424         fbcAddDefLib( "gcc" )
 3425         fbcAddDefLib( "fbgfx" )
 3426         fbcAddDefLib( "openxdk" )
 3427         fbcAddDefLib( "hal" )
 3428         fbcAddDefLib( "c" )
 3429         fbcAddDefLib( "usb" )
 3430         fbcAddDefLib( "xboxkrnl" )
 3431         fbcAddDefLib( "m" )
 3432 
 3433         '' profiling?
 3434         if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
 3435             fbcAddDefLib( "gmon" )
 3436         end if
 3437 
 3438     end select
 3439 
 3440 end sub
 3441 
 3442 private sub hPrintOptions( byval verbose as integer )
 3443     '' Note: must print each line separately to let the rtlib print the
 3444     '' proper line endings even if redirected to file/pipe, hard-coding \n
 3445     '' here isn't enough for DOS/Windows.
 3446 
 3447     print "usage: fbc [options] <input files>"
 3448     print "input files:"
 3449     print "  *.a = static library, *.o = object file, *.bas = source"
 3450     print "  *.rc = resource script, *.res = compiled resource (win32)"
 3451     print "  *.xpm = icon resource (*nix/*bsd)"
 3452     print "options:"
 3453     print "  @<file>          Read more command line arguments from a file"
 3454     print "  -a <file>        Treat file as .o/.a input file"
 3455     print "  -arch <type>     Set target architecture (default: 486)"
 3456     print "  -asm att|intel   Set asm format (-gen gcc|llvm, x86 or x86_64 only)"
 3457     print "  -b <file>        Treat file as .bas input file"
 3458     print "  -c               Compile only, do not link"
 3459     print "  -C               Preserve temporary .o files"
 3460     print "  -d <name>[=<val>]  Add a global #define"
 3461     print "  -dll             Same as -dylib"
 3462     print "  -dylib           Create a DLL (win32) or shared library (*nix/*BSD)"
 3463     print "  -e               Enable runtime error checking"
 3464 
 3465     if( verbose ) then
 3466     print "  -earray          Enable array bounds checking"
 3467     print "  -eassert         Enable assert() and assertwarn() checking"
 3468     print "  -edebug          Enable __FB_DEBUG__"
 3469     print "  -edebuginfo      Add debug info"
 3470     print "  -elocation       Enable error location reporting"
 3471     print "  -enullptr        Enable null-pointer checking"
 3472     end if
 3473 
 3474     print "  -ex              -e plus RESUME support"
 3475     print "  -exx             -ex plus array bounds/null-pointer checking"
 3476     print "  -export          Export symbols for dynamic linkage"
 3477     print "  -forcelang <name>  Override #lang statements in source code"
 3478     print "  -fpmode fast|precise  Select floating-point math accuracy/speed"
 3479     print "  -fpu x87|sse     Set target FPU"
 3480     print "  -g               Add debug info, enable __FB_DEBUG__, and enable assert()"
 3481 
 3482     if( verbose ) then
 3483     print "  -gen gas         Select GNU gas assembler backend"
 3484     print "  -gen gcc         Select GNU gcc C backend"
 3485     print "  -gen llvm        Select LLVM backend"
 3486     else
 3487     print "  -gen gas|gcc|llvm  Select code generation backend"
 3488     end if
 3489 
 3490     print "  [-]-help         Show this help output"
 3491     print "  -i <path>        Add an include file search path"
 3492     print "  -include <file>  Pre-#include a file for each input .bas"
 3493     print "  -l <name>        Link in a library"
 3494     print "  -lang <name>     Select FB dialect: fb, deprecated, fblite, qb"
 3495     print "  -lib             Create a static library"
 3496     print "  -m <name>        Specify main module (default if not -c: first input .bas)"
 3497     print "  -map <file>      Save linking map to file"
 3498     print "  -maxerr <n>      Only show <n> errors"
 3499     print "  -mt              Use thread-safe FB runtime"
 3500     print "  -nodeflibs       Do not include the default libraries"
 3501     print "  -noerrline       Do not show source context in error messages"
 3502     print "  -noobjinfo       Do not read/write compile-time info from/to .o and .a files"
 3503     print "  -nostrip         Do not strip symbol information from the output file"
 3504     print "  -o <file>        Set .o (or -pp .bas) file name for prev/next input file"
 3505     print "  -O <value>       Optimization level (default: 0)"
 3506     print "  -p <path>        Add a library search path"
 3507     print "  -pic             Generate position-independent code (non-x86 Unix shared libs)"
 3508     print "  -pp              Write out preprocessed input file (.pp.bas) only"
 3509     print "  -prefix <path>   Set the compiler prefix path"
 3510     print "  -print host|target  Display host/target system name"
 3511     print "  -print fblibdir  Display the compiler's lib/ path"
 3512     print "  -print x         Display output binary/library file name (if known)"
 3513     if( verbose ) then
 3514     print "  -print sha-1     Display compiler's source code commit sha-1 (if known)"
 3515     end if
 3516     print "  -profile         Enable function profiling"
 3517     print "  -r               Write out .asm/.c/.ll (-gen gas/gcc/llvm) only"
 3518     print "  -rr              Write out the final .asm only"
 3519     print "  -R               Preserve temporary .asm/.c/.ll/.def files"
 3520     print "  -RR              Preserve the final .asm file"
 3521     print "  -s console|gui   Select win32 subsystem"
 3522     print "  -showincludes    Display a tree of file names of #included files"
 3523     print "  -static          Prefer static libraries over dynamic ones when linking"
 3524     print "  -strip           Omit all symbol information from the output file"
 3525     print "  -t <value>       Set .exe stack size in kbytes, default: 1024 (win32/dos)"
 3526     if( verbose ) then
 3527     '' !!! TODO !!! provide more examples of available targets
 3528     print "  -target <name>   Set cross-compilation target"
 3529     else
 3530     print "  -target <name>   Set cross-compilation target"
 3531     end if
 3532     print "  -title <name>    Set XBE display title (xbox)"
 3533     print "  -v               Be verbose"
 3534     print "  -vec <n>         Automatic vectorization level (default: 0)"
 3535     print "  [-]-version      Show compiler version"
 3536     print "  -w all|pedantic|<n>  Set min warning level: all, pedantic or a value"
 3537     print "  -Wa <a,b,c>      Pass options to 'as'"
 3538     print "  -Wc <a,b,c>      Pass options to 'gcc' (-gen gcc) or 'llc' (-gen llvm)"
 3539     print "  -Wl <a,b,c>      Pass options to 'ld'"
 3540     print "  -x <file>        Set output executable/library file name"
 3541 
 3542     if( verbose ) then
 3543     print "  -z gosub-setjmp  Use setjmp/longjmp to implement GOSUB"
 3544     print "  -z valist-as-ptr Use pointer expressions to implement CVA_*() macros"
 3545     end if
 3546 
 3547 end sub
 3548 
 3549 private sub hAppendConfigInfo( byref config as string, byval info as zstring ptr )
 3550     if( len( config ) > 0 ) then
 3551         config += ", "
 3552     end if
 3553     config += *info
 3554 end sub
 3555 
 3556 private sub hPrintVersion( byval verbose as integer )
 3557     dim as string config
 3558 
 3559     print "FreeBASIC Compiler - Version " + FB_VERSION + _
 3560         " (" + FB_BUILD_DATE_ISO + "), built for " + fbGetHostId( ) + " (" & fbGetHostBits( ) & "bit)"
 3561     print "Copyright (C) 2004-2019 The FreeBASIC development team."
 3562 
 3563     #ifdef ENABLE_STANDALONE
 3564         hAppendConfigInfo( config, "standalone" )
 3565     #endif
 3566 
 3567     #ifdef ENABLE_PREFIX
 3568         hAppendConfigInfo( config, "prefix: '" + ENABLE_PREFIX + "'" )
 3569     #endif
 3570 
 3571     if( len( config ) > 0 ) then
 3572         print config
 3573     end if
 3574 
 3575     if( verbose ) then
 3576         fbcPrintTargetInfo( )
 3577         if( FB_BUILD_SHA1 > "" ) then
 3578             print "source sha-1: " & FB_BUILD_SHA1
 3579         end if
 3580     end if
 3581 end sub
 3582 
 3583     fbcInit( )
 3584 
 3585     if( __FB_ARGC__ = 1 ) then
 3586         hPrintOptions( FALSE )
 3587         fbcEnd( 1 )
 3588     end if
 3589 
 3590     hParseArgs( __FB_ARGC__, __FB_ARGV__ )
 3591 
 3592     if( fbc.showversion ) then
 3593         hPrintVersion( fbc.verbose )
 3594         fbcEnd( 0 )
 3595     end if
 3596 
 3597     if( fbc.verbose ) then
 3598         hPrintVersion( FALSE )
 3599     end if
 3600 
 3601     '' Show help if --help was given
 3602     if( fbc.showhelp ) then
 3603         hPrintOptions( fbc.verbose )
 3604         fbcEnd( 1 )
 3605     end if
 3606 
 3607     fbcDeterminePrefix( )
 3608     fbcSetupCompilerPaths( )
 3609 
 3610     if( fbc.verbose ) then
 3611         fbcPrintTargetInfo( )
 3612     end if
 3613 
 3614     '' Tell the compiler about the default include path (added after
 3615     '' the command line ones, so those will be searched first)
 3616     fbAddIncludePath( fbc.incpath )
 3617 
 3618     var have_input_files = (listGetHead( @fbc.modules   ) <> NULL) or _
 3619                            (listGetHead( @fbc.objlist   ) <> NULL) or _
 3620                            (listGetHead( @fbc.libs.list ) <> NULL) or _
 3621                            (listGetHead( @fbc.libfiles  ) <> NULL)
 3622 
 3623     '' Answer -print query, if any, and stop
 3624     '' The -print option is intended to allow shell scripts, makefiles, etc.
 3625     '' to query information from fbc.
 3626     if( fbc.print >= 0 ) then
 3627         select case( fbc.print )
 3628         case PRINT_HOST
 3629             print fbGetHostId( )
 3630         case PRINT_TARGET
 3631             print fbGetTargetId( )
 3632         case PRINT_X
 3633             '' If we have input files, -print x should give the output name that we'd normally get.
 3634             '' However, a plain "fbc -print x" without input files should just give the .exe extension.
 3635             if( have_input_files ) then
 3636                 fbcDetermineMainName( )
 3637             end if
 3638             hSetOutName( )
 3639             print fbc.outname
 3640         case PRINT_FBLIBDIR
 3641             print fbc.libpath
 3642         case PRINT_SHA1
 3643             print FB_BUILD_SHA1
 3644         end select
 3645         fbcEnd( 0 )
 3646     end if
 3647 
 3648     fbcDetermineMainName( )
 3649 
 3650     '' Show help if there are no input files
 3651     if( have_input_files = FALSE ) then
 3652         hPrintOptions( fbc.verbose )
 3653         fbcEnd( 1 )
 3654     end if
 3655 
 3656     ''
 3657     '' Compile .bas modules
 3658     ''
 3659     hCompileModules( )
 3660 
 3661     if( hCompileXpm( ) = FALSE ) then
 3662         fbcEnd( 1 )
 3663     end if
 3664 
 3665     if( fbc.emitasmonly ) then
 3666         fbcEnd( 0 )
 3667     end if
 3668 
 3669     if( fbGetOption( FB_COMPOPT_BACKEND ) <> FB_BACKEND_GAS ) then
 3670         ''
 3671         '' Compile intermediate .c modules produced by -gen gcc
 3672         ''
 3673         hCompileStage2Modules( )
 3674     end if
 3675 
 3676     if( fbc.emitfinalasmonly ) then
 3677         fbcEnd( 0 )
 3678     end if
 3679 
 3680     ''
 3681     '' Assemble into .o files
 3682     ''
 3683     hAssembleModules( )
 3684     hAssembleRcs( )
 3685     hAssembleXpm( )
 3686 
 3687     '' Stop for -c
 3688     if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_OBJECT ) then
 3689         fbcEnd( 0 )
 3690     end if
 3691 
 3692     '' Set the default lib paths before scanning for other libs
 3693     hSetDefaultLibPaths( )
 3694 
 3695     '' Scan objects and libraries for more libraries and paths,
 3696     '' before adding the default libs, which don't need to be searched,
 3697     '' because they don't contain objinfo anyways.
 3698     if( fbGetOption( FB_COMPOPT_OBJINFO ) and (not fbIsCrossComp( )) ) then
 3699         hCollectObjinfo( )
 3700     end if
 3701 
 3702     if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_STATICLIB ) then
 3703         if( hArchiveFiles( ) = FALSE ) then
 3704             fbcEnd( 1 )
 3705         end if
 3706         fbcEnd( 0 )
 3707     end if
 3708 
 3709     '' Link
 3710 
 3711     '' Add default libs for linking, unless -nodeflibs was given
 3712     '' Note: These aren't added into objinfo sections of objects or
 3713     '' static libraries. Only the non-default libs are needed there.
 3714     if( fbc.nodeflibs = FALSE ) then
 3715         hAddDefaultLibs( )
 3716     end if
 3717 
 3718     if( hLinkFiles( ) = FALSE ) then
 3719         fbcEnd( 1 )
 3720     end if
 3721 
 3722     fbcEnd( 0 )