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