summaryrefslogtreecommitdiff
path: root/closures/compiler/pmodules.pas
diff options
context:
space:
mode:
authorblaise <blaise@3ad0048d-3df7-0310-abae-a5850022a9f2>2012-01-20 16:59:47 +0000
committerblaise <blaise@3ad0048d-3df7-0310-abae-a5850022a9f2>2012-01-20 16:59:47 +0000
commit350adcb4b28481f4ae121a996c9f43dc019da18b (patch)
tree7706bc04e2d90f0667dc7131e8d510d7d6faea12 /closures/compiler/pmodules.pas
parent3b26cada0c5d0710b95d3603e9f59cea429f7b79 (diff)
downloadfpc-350adcb4b28481f4ae121a996c9f43dc019da18b.tar.gz
starting from r20123
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/blaise@20126 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'closures/compiler/pmodules.pas')
-rw-r--r--closures/compiler/pmodules.pas2523
1 files changed, 2523 insertions, 0 deletions
diff --git a/closures/compiler/pmodules.pas b/closures/compiler/pmodules.pas
new file mode 100644
index 0000000000..d8c64a1124
--- /dev/null
+++ b/closures/compiler/pmodules.pas
@@ -0,0 +1,2523 @@
+{
+ Copyright (c) 1998-2008 by Florian Klaempfl
+
+ Handles the parsing and loading of the modules (ppufiles)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit pmodules;
+
+{$i fpcdefs.inc}
+
+interface
+
+ procedure proc_unit;
+ procedure proc_package;
+ procedure proc_program(islibrary : boolean);
+
+implementation
+
+ uses
+ SysUtils,
+ globtype,version,systems,tokens,
+ cutils,cfileutl,cclasses,comphook,
+ globals,verbose,fmodule,finput,fppu,
+ symconst,symbase,symtype,symdef,symsym,symtable,
+ wpoinfo,
+ aasmtai,aasmdata,aasmcpu,aasmbase,
+ cgbase,cgobj,
+ nbas,nutils,ncgutil,
+ link,assemble,import,export,gendef,ppu,comprsrc,dbgbase,
+ cresstr,procinfo,
+ pexports,
+ objcgutl,
+ wpobase,
+ scanner,pbase,pexpr,psystem,psub,pdecsub,ptype,
+ cpuinfo;
+
+
+ procedure create_objectfile;
+ var
+ DLLScanner : TDLLScanner;
+ s : string;
+ KeepShared : TCmdStrList;
+ begin
+ { try to create import entries from system dlls }
+ if (tf_has_dllscanner in target_info.flags) and
+ (not current_module.linkOtherSharedLibs.Empty) then
+ begin
+ { Init DLLScanner }
+ if assigned(CDLLScanner[target_info.system]) then
+ DLLScanner:=CDLLScanner[target_info.system].Create
+ else
+ internalerror(200104121);
+ KeepShared:=TCmdStrList.Create;
+ { Walk all shared libs }
+ While not current_module.linkOtherSharedLibs.Empty do
+ begin
+ S:=current_module.linkOtherSharedLibs.Getusemask(link_always);
+ if not DLLScanner.scan(s) then
+ KeepShared.Concat(s);
+ end;
+ DLLscanner.Free;
+ { Recreate import section }
+ if (target_info.system in [system_i386_win32,system_i386_wdosx]) then
+ begin
+ if assigned(current_asmdata.asmlists[al_imports]) then
+ current_asmdata.asmlists[al_imports].clear
+ else
+ current_asmdata.asmlists[al_imports]:=TAsmList.Create;
+ importlib.generatelib;
+ end;
+ { Readd the not processed files }
+ while not KeepShared.Empty do
+ begin
+ s:=KeepShared.GetFirst;
+ current_module.linkOtherSharedLibs.add(s,link_always);
+ end;
+ KeepShared.Free;
+ end;
+
+ { Start and end module debuginfo, at least required for stabs
+ to insert n_sourcefile lines }
+ if (cs_debuginfo in current_settings.moduleswitches) or
+ (cs_use_lineinfo in current_settings.globalswitches) then
+ current_debuginfo.insertmoduleinfo;
+
+ { create the .s file and assemble it }
+ GenerateAsm(false);
+
+ { Also create a smartlinked version ? }
+ if create_smartlink_library then
+ begin
+ GenerateAsm(true);
+ if (af_needar in target_asm.flags) then
+ Linker.MakeStaticLibrary;
+ end;
+
+ { resource files }
+ CompileResourceFiles;
+ end;
+
+
+ procedure insertobjectfile;
+ { Insert the used object file for this unit in the used list for this unit }
+ begin
+ current_module.linkunitofiles.add(current_module.objfilename^,link_static);
+ current_module.flags:=current_module.flags or uf_static_linked;
+
+ if create_smartlink_library then
+ begin
+ current_module.linkunitstaticlibs.add(current_module.staticlibfilename^,link_smart);
+ current_module.flags:=current_module.flags or uf_smart_linked;
+ end;
+ end;
+
+
+ procedure create_dwarf_frame;
+ begin
+ { Dwarf conflicts with smartlinking in separate .a files }
+ if create_smartlink_library then
+ exit;
+ { Call frame information }
+ { MWE: we write our own info, so dwarf asm support is not really needed }
+ { if (af_supports_dwarf in target_asm.flags) and }
+ { CFI is currently broken for Darwin }
+ if not(target_info.system in systems_darwin) and
+ (
+ (tf_needs_dwarf_cfi in target_info.flags) or
+ (paratargetdbg in [dbg_dwarf2, dbg_dwarf3])
+ ) then
+ begin
+ current_asmdata.asmlists[al_dwarf_frame].Free;
+ current_asmdata.asmlists[al_dwarf_frame] := TAsmList.create;
+ current_asmdata.asmcfi.generate_code(current_asmdata.asmlists[al_dwarf_frame]);
+ end;
+ end;
+
+
+ procedure InsertThreadvarTablesTable;
+ var
+ hp : tused_unit;
+ ltvTables : TAsmList;
+ count : longint;
+ begin
+ if (tf_section_threadvars in target_info.flags) then
+ exit;
+ ltvTables:=TAsmList.Create;
+ count:=0;
+ hp:=tused_unit(usedunits.first);
+ while assigned(hp) do
+ begin
+ If (hp.u.flags and uf_threadvars)=uf_threadvars then
+ begin
+ ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',hp.u.globalsymtable,''),0));
+ inc(count);
+ end;
+ hp:=tused_unit(hp.next);
+ end;
+ { Add program threadvars, if any }
+ If (current_module.flags and uf_threadvars)=uf_threadvars then
+ begin
+ ltvTables.concat(Tai_const.Createname(make_mangledname('THREADVARLIST',current_module.localsymtable,''),0));
+ inc(count);
+ end;
+ { Insert TableCount at start }
+ ltvTables.insert(Tai_const.Create_32bit(count));
+ { insert in data segment }
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'FPC_THREADVARTABLES',sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('FPC_THREADVARTABLES',AT_DATA,0));
+ current_asmdata.asmlists[al_globals].concatlist(ltvTables);
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('FPC_THREADVARTABLES'));
+ ltvTables.free;
+ end;
+
+ procedure AddToThreadvarList(p:TObject;arg:pointer);
+ var
+ ltvTable : TAsmList;
+ begin
+ ltvTable:=TAsmList(arg);
+ if (tsym(p).typ=staticvarsym) and
+ (vo_is_thread_var in tstaticvarsym(p).varoptions) then
+ begin
+ { address of threadvar }
+ ltvTable.concat(tai_const.Createname(tstaticvarsym(p).mangledname,0));
+ { size of threadvar }
+ ltvTable.concat(tai_const.create_32bit(tstaticvarsym(p).getsize));
+ end;
+ end;
+
+
+ procedure InsertThreadvars;
+ var
+ s : string;
+ ltvTable : TAsmList;
+ begin
+ if (tf_section_threadvars in target_info.flags) then
+ exit;
+ ltvTable:=TAsmList.create;
+ if assigned(current_module.globalsymtable) then
+ current_module.globalsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
+ current_module.localsymtable.SymList.ForEachCall(@AddToThreadvarList,ltvTable);
+ if ltvTable.first<>nil then
+ begin
+ s:=make_mangledname('THREADVARLIST',current_module.localsymtable,'');
+ { end of the list marker }
+ ltvTable.concat(tai_const.create_sym(nil));
+ { add to datasegment }
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
+ current_asmdata.asmlists[al_globals].concatlist(ltvTable);
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
+ current_module.flags:=current_module.flags or uf_threadvars;
+ end;
+ ltvTable.Free;
+ end;
+
+ procedure InsertRuntimeInits(const prefix:string;list:TLinkedList;unitflag:cardinal);
+ var
+ s: string;
+ item: TTCInitItem;
+ begin
+ item:=TTCInitItem(list.First);
+ if item=nil then
+ exit;
+ s:=make_mangledname(prefix,current_module.localsymtable,'');
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,s,sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(s,AT_DATA,0));
+ repeat
+ { optimize away unused local/static symbols }
+ if (item.sym.refs>0) or (item.sym.owner.symtabletype=globalsymtable) then
+ begin
+ { address to initialize }
+ current_asmdata.asmlists[al_globals].concat(Tai_const.createname(item.sym.mangledname, item.offset));
+ { value with which to initialize }
+ current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(item.datalabel));
+ end;
+ item:=TTCInitItem(item.Next);
+ until item=nil;
+ { end-of-list marker }
+ current_asmdata.asmlists[al_globals].concat(Tai_const.Create_sym(nil));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(s));
+ current_module.flags:=current_module.flags or unitflag;
+ end;
+
+ procedure InsertRuntimeInitsTablesTable(const prefix,tablename:string;unitflag:cardinal);
+ var
+ hp: tused_unit;
+ hlist: TAsmList;
+ count: longint;
+ begin
+ hlist:=TAsmList.Create;
+ count:=0;
+ hp:=tused_unit(usedunits.first);
+ while assigned(hp) do
+ begin
+ if (hp.u.flags and unitflag)=unitflag then
+ begin
+ hlist.concat(Tai_const.Createname(make_mangledname(prefix,hp.u.globalsymtable,''),0));
+ inc(count);
+ end;
+ hp:=tused_unit(hp.next);
+ end;
+ { Add items from program, if any }
+ if (current_module.flags and unitflag)=unitflag then
+ begin
+ hlist.concat(Tai_const.Createname(make_mangledname(prefix,current_module.localsymtable,''),0));
+ inc(count);
+ end;
+ { Insert TableCount at start }
+ hlist.insert(Tai_const.Create_32bit(count));
+ { insert in data segment }
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,tablename,sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global(tablename,AT_DATA,0));
+ current_asmdata.asmlists[al_globals].concatlist(hlist);
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname(tablename));
+ hlist.free;
+ end;
+
+ procedure InsertWideInits;
+ begin
+ InsertRuntimeInits('WIDEINITS',current_asmdata.WideInits,uf_wideinits);
+ end;
+
+ procedure InsertResStrInits;
+ begin
+ InsertRuntimeInits('RESSTRINITS',current_asmdata.ResStrInits,uf_resstrinits);
+ end;
+
+ procedure InsertWideInitsTablesTable;
+ begin
+ InsertRuntimeInitsTablesTable('WIDEINITS','FPC_WIDEINITTABLES',uf_wideinits);
+ end;
+
+ procedure InsertResStrTablesTable;
+ begin
+ InsertRuntimeInitsTablesTable('RESSTRINITS','FPC_RESSTRINITTABLES',uf_resstrinits);
+ end;
+
+ Function CheckResourcesUsed : boolean;
+ var
+ hp : tused_unit;
+ found : Boolean;
+ begin
+ CheckResourcesUsed:=tf_has_winlike_resources in target_info.flags;
+ if not CheckResourcesUsed then exit;
+
+ hp:=tused_unit(usedunits.first);
+ found:=((current_module.flags and uf_has_resourcefiles)=uf_has_resourcefiles);
+ If not found then
+ While Assigned(hp) and not found do
+ begin
+ Found:=((hp.u.flags and uf_has_resourcefiles)=uf_has_resourcefiles);
+ hp:=tused_unit(hp.next);
+ end;
+ CheckResourcesUsed:=found;
+ end;
+
+ Procedure InsertResourceInfo(ResourcesUsed : boolean);
+
+ var
+ ResourceInfo : TAsmList;
+
+ begin
+ if (target_res.id in [res_elf,res_macho]) then
+ begin
+ ResourceInfo:=TAsmList.Create;
+
+ maybe_new_object_file(ResourceInfo);
+ new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
+ ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
+ if ResourcesUsed then
+ { Valid pointer to resource information }
+ ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
+ else
+ { Nil pointer to resource information }
+ {$IFNDEF cpu64bitaddr}
+ ResourceInfo.Concat(Tai_const.Create_32bit(0));
+ {$ELSE}
+ ResourceInfo.Concat(Tai_const.Create_64bit(0));
+ {$ENDIF}
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
+ ResourceInfo.free;
+ end;
+ end;
+
+
+ Procedure InsertResourceTablesTable;
+ var
+ hp : tmodule;
+ ResourceStringTables : tasmlist;
+ count : longint;
+ begin
+ ResourceStringTables:=tasmlist.Create;
+ count:=0;
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ If (hp.flags and uf_has_resourcestrings)=uf_has_resourcestrings then
+ begin
+ ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'START'),0));
+ ResourceStringTables.concat(Tai_const.Createname(make_mangledname('RESSTR',hp.localsymtable,'END'),0));
+ inc(count);
+ end;
+ hp:=tmodule(hp.next);
+ end;
+ { Insert TableCount at start }
+ ResourceStringTables.insert(Tai_const.Create_pint(count));
+ { Add to data segment }
+ maybe_new_object_file(current_asmdata.AsmLists[al_globals]);
+ new_section(current_asmdata.AsmLists[al_globals],sec_data,'FPC_RESOURCESTRINGTABLES',sizeof(pint));
+ current_asmdata.AsmLists[al_globals].concat(Tai_symbol.Createname_global('FPC_RESOURCESTRINGTABLES',AT_DATA,0));
+ current_asmdata.AsmLists[al_globals].concatlist(ResourceStringTables);
+ current_asmdata.AsmLists[al_globals].concat(Tai_symbol_end.Createname('FPC_RESOURCESTRINGTABLES'));
+ ResourceStringTables.free;
+ end;
+
+ procedure AddToStructInits(p:TObject;arg:pointer);
+ var
+ StructList: TFPList absolute arg;
+ begin
+ if (tdef(p).typ in [objectdef,recorddef]) and
+ ([oo_has_class_constructor,oo_has_class_destructor] * tabstractrecorddef(p).objectoptions <> []) then
+ StructList.Add(p);
+ end;
+
+ procedure InsertInitFinalTable;
+ var
+ hp : tused_unit;
+ unitinits : TAsmList;
+ count : longint;
+
+ procedure write_struct_inits(u: tmodule);
+ var
+ i: integer;
+ structlist: TFPList;
+ pd: tprocdef;
+ begin
+ structlist := TFPList.Create;
+ if assigned(u.globalsymtable) then
+ u.globalsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
+ u.localsymtable.DefList.ForEachCall(@AddToStructInits,structlist);
+ { write structures }
+ for i := 0 to structlist.Count - 1 do
+ begin
+ pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_constructor);
+ if assigned(pd) then
+ unitinits.concat(Tai_const.Createname(pd.mangledname,0))
+ else
+ unitinits.concat(Tai_const.Create_pint(0));
+ pd := tabstractrecorddef(structlist[i]).find_procdef_bytype(potype_class_destructor);
+ if assigned(pd) then
+ unitinits.concat(Tai_const.Createname(pd.mangledname,0))
+ else
+ unitinits.concat(Tai_const.Create_pint(0));
+ inc(count);
+ end;
+ structlist.free;
+ end;
+
+ begin
+ unitinits:=TAsmList.Create;
+ count:=0;
+ hp:=tused_unit(usedunits.first);
+ while assigned(hp) do
+ begin
+ { insert class constructors/destructors of the unit }
+ if (hp.u.flags and uf_classinits) <> 0 then
+ write_struct_inits(hp.u);
+ { call the unit init code and make it external }
+ if (hp.u.flags and (uf_init or uf_finalize))<>0 then
+ begin
+ if (hp.u.flags and uf_init)<>0 then
+ unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',hp.u.globalsymtable,''),0))
+ else
+ unitinits.concat(Tai_const.Create_sym(nil));
+ if (hp.u.flags and uf_finalize)<>0 then
+ unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',hp.u.globalsymtable,''),0))
+ else
+ unitinits.concat(Tai_const.Create_sym(nil));
+ inc(count);
+ end;
+ hp:=tused_unit(hp.next);
+ end;
+ { insert class constructors/destructor of the program }
+ if (current_module.flags and uf_classinits) <> 0 then
+ write_struct_inits(current_module);
+ { Insert initialization/finalization of the program }
+ if (current_module.flags and (uf_init or uf_finalize))<>0 then
+ begin
+ if (current_module.flags and uf_init)<>0 then
+ unitinits.concat(Tai_const.Createname(make_mangledname('INIT$',current_module.localsymtable,''),0))
+ else
+ unitinits.concat(Tai_const.Create_sym(nil));
+ if (current_module.flags and uf_finalize)<>0 then
+ unitinits.concat(Tai_const.Createname(make_mangledname('FINALIZE$',current_module.localsymtable,''),0))
+ else
+ unitinits.concat(Tai_const.Create_sym(nil));
+ inc(count);
+ end;
+ { Insert TableCount,InitCount at start }
+ unitinits.insert(Tai_const.Create_32bit(0));
+ unitinits.insert(Tai_const.Create_32bit(count));
+ { Add to data segment }
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'INITFINAL',sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('INITFINAL',AT_DATA,0));
+ current_asmdata.asmlists[al_globals].concatlist(unitinits);
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol_end.Createname('INITFINAL'));
+ unitinits.free;
+ end;
+
+
+ procedure InsertMemorySizes;
+{$IFDEF POWERPC}
+ var
+ stkcookie: string;
+{$ENDIF POWERPC}
+ begin
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ { Insert Ident of the compiler in the .fpc.version section }
+ new_section(current_asmdata.asmlists[al_globals],sec_fpc,'version',const_align(32));
+ current_asmdata.asmlists[al_globals].concat(Tai_string.Create('FPC '+full_version_string+
+ ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname));
+ if not(tf_no_generic_stackcheck in target_info.flags) then
+ begin
+ { stacksize can be specified and is now simulated }
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'__stklen', sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stklen',AT_DATA,sizeof(pint)));
+ current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(stacksize));
+ end;
+{$IFDEF POWERPC}
+ { AmigaOS4 "stack cookie" support }
+ if ( target_info.system = system_powerpc_amiga ) then
+ begin
+ { this symbol is needed to ignite powerpc amigaos' }
+ { stack allocation magic for us with the given stack size. }
+ { note: won't work for m68k amigaos or morphos. (KB) }
+ str(stacksize,stkcookie);
+ stkcookie:='$STACK: '+stkcookie+#0;
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'__stack_cookie',length(stkcookie));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__stack_cookie',AT_DATA,length(stkcookie)));
+ current_asmdata.asmlists[al_globals].concat(Tai_string.Create(stkcookie));
+ end;
+{$ENDIF POWERPC}
+ { Initial heapsize }
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'__heapsize',sizeof(pint));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__heapsize',AT_DATA,sizeof(pint)));
+ current_asmdata.asmlists[al_globals].concat(Tai_const.Create_pint(heapsize));
+ { Initial heapsize }
+ maybe_new_object_file(current_asmdata.asmlists[al_globals]);
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'__fpc_valgrind',sizeof(boolean));
+ current_asmdata.asmlists[al_globals].concat(Tai_symbol.Createname_global('__fpc_valgrind',AT_DATA,sizeof(boolean)));
+ current_asmdata.asmlists[al_globals].concat(Tai_const.create_8bit(byte(cs_gdb_valgrind in current_settings.globalswitches)));
+ end;
+
+
+ procedure AddUnit(const s:string);
+ var
+ hp : tppumodule;
+ unitsym : tunitsym;
+ begin
+ { load unit }
+ hp:=registerunit(current_module,s,'');
+ hp.loadppu;
+ hp.adddependency(current_module);
+ { add to symtable stack }
+ symtablestack.push(hp.globalsymtable);
+ if (m_mac in current_settings.modeswitches) and
+ assigned(hp.globalmacrosymtable) then
+ macrosymtablestack.push(hp.globalmacrosymtable);
+ { insert unitsym }
+ unitsym:=tunitsym.create(s,hp);
+ inc(unitsym.refs);
+ tabstractunitsymtable(current_module.localsymtable).insertunit(unitsym);
+ { add to used units }
+ current_module.addusedunit(hp,false,unitsym);
+ end;
+
+
+ procedure maybeloadvariantsunit;
+ var
+ hp : tmodule;
+ begin
+ { Do we need the variants unit? Skip this
+ for VarUtils unit for bootstrapping }
+ if (current_module.flags and uf_uses_variants=0) or
+ (current_module.modulename^='VARUTILS') then
+ exit;
+ { Variants unit already loaded? }
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ if hp.modulename^='VARIANTS' then
+ exit;
+ hp:=tmodule(hp.next);
+ end;
+ { Variants unit is not loaded yet, load it now }
+ Message(parser_w_implicit_uses_of_variants_unit);
+ AddUnit('variants');
+ end;
+
+
+ function MaybeRemoveResUnit : boolean;
+ var
+ resources_used : boolean;
+ hp : tmodule;
+ uu : tused_unit;
+ unitname : shortstring;
+ begin
+ { We simply remove the unit from:
+ - usedunit list, so that things like init/finalization table won't
+ contain references to this unit
+ - loaded_units list, so that the unit object file doesn't get linked
+ with the executable. }
+ { Note: on windows we always need resources! }
+ resources_used:=(target_info.system in systems_all_windows)
+ or CheckResourcesUsed;
+ if (not resources_used) and (tf_has_winlike_resources in target_info.flags) then
+ begin
+ { resources aren't used, so we don't need this unit }
+ if target_res.id=res_ext then
+ unitname:='FPEXTRES'
+ else
+ unitname:='FPINTRES';
+ Message1(unit_u_unload_resunit,unitname);
+ { find the module }
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ if hp.is_unit and (hp.modulename^=unitname) then break;
+ hp:=tmodule(hp.next);
+ end;
+ if not assigned(hp) then
+ internalerror(200801071);
+ { find its tused_unit in the global list }
+ uu:=tused_unit(usedunits.first);
+ while assigned(uu) do
+ begin
+ if uu.u=hp then break;
+ uu:=tused_unit(uu.next);
+ end;
+ if not assigned(uu) then
+ internalerror(200801072);
+ { remove the tused_unit }
+ usedunits.Remove(uu);
+ uu.Free;
+ { remove the module }
+ loaded_units.Remove(hp);
+ unloaded_units.Concat(hp);
+ end;
+ MaybeRemoveResUnit:=resources_used;
+ end;
+
+
+ procedure loaddefaultunits;
+ begin
+ { we are going to rebuild the symtablestack, clear it first }
+ symtablestack.clear;
+ macrosymtablestack.clear;
+
+ { macro symtable }
+ macrosymtablestack.push(initialmacrosymtable);
+
+ { are we compiling the system unit? }
+ if (cs_compilesystem in current_settings.moduleswitches) then
+ begin
+ systemunit:=tglobalsymtable(current_module.localsymtable);
+ { create system defines }
+ create_intern_symbols;
+ create_intern_types;
+ { Set the owner of errorsym and errortype to symtable to
+ prevent crashes when accessing .owner }
+ generrorsym.owner:=systemunit;
+ generrordef.owner:=systemunit;
+ exit;
+ end;
+
+ { insert the system unit, it is allways the first. Load also the
+ internal types from the system unit }
+ AddUnit('system');
+ systemunit:=tglobalsymtable(symtablestack.top);
+ load_intern_types;
+
+ { Set the owner of errorsym and errortype to symtable to
+ prevent crashes when accessing .owner }
+ generrorsym.owner:=systemunit;
+ generrordef.owner:=systemunit;
+
+ { Units only required for main module }
+ if not(current_module.is_unit) then
+ begin
+ { Heaptrc unit, load heaptrace before any other units especially objpas }
+ if (cs_use_heaptrc in current_settings.globalswitches) then
+ AddUnit('heaptrc');
+ { Lineinfo unit }
+ if (cs_use_lineinfo in current_settings.globalswitches) then begin
+ if (paratargetdbg = dbg_stabs) then
+ AddUnit('lineinfo')
+ else
+ AddUnit('lnfodwrf');
+ end;
+ { Valgrind requires c memory manager }
+ if (cs_gdb_valgrind in current_settings.globalswitches) then
+ AddUnit('cmem');
+{$ifdef cpufpemu}
+ { Floating point emulation unit?
+ softfpu must be in the system unit anyways (FK)
+ if (cs_fp_emulation in current_settings.moduleswitches) and not(target_info.system in system_wince) then
+ AddUnit('softfpu');
+ }
+{$endif cpufpemu}
+ { Which kind of resource support?
+ Note: if resources aren't used this unit will be removed later,
+ otherwise we need it here since it must be loaded quite early }
+ if (tf_has_winlike_resources in target_info.flags) then
+ if target_res.id=res_ext then
+ AddUnit('fpextres')
+ else
+ AddUnit('fpintres');
+ end;
+ { Objpas unit? }
+ if m_objpas in current_settings.modeswitches then
+ AddUnit('objpas');
+
+ { Macpas unit? }
+ if m_mac in current_settings.modeswitches then
+ AddUnit('macpas');
+
+ if m_iso in current_settings.modeswitches then
+ AddUnit('iso7185');
+
+ { Objective-C support unit? }
+ if (m_objectivec1 in current_settings.modeswitches) then
+ begin
+ { interface to Objective-C run time }
+ AddUnit('objc');
+ loadobjctypes;
+ { NSObject }
+ if not(current_module.is_unit) or
+ (current_module.modulename^<>'OBJCBASE') then
+ AddUnit('objcbase');
+ end;
+ { Profile unit? Needed for go32v2 only }
+ if (cs_profile in current_settings.moduleswitches) and
+ (target_info.system in [system_i386_go32v2,system_i386_watcom]) then
+ AddUnit('profile');
+ if (cs_load_fpcylix_unit in current_settings.globalswitches) then
+ begin
+ AddUnit('fpcylix');
+ AddUnit('dynlibs');
+ end;
+
+ { CPU targets with microcontroller support can add a controller specific unit }
+{$if defined(ARM) or defined(AVR)}
+ if (target_info.system in systems_embedded) and (current_settings.controllertype<>ct_none) and
+ (embedded_controllers[current_settings.controllertype].controllerunitstr<>'') then
+ AddUnit(embedded_controllers[current_settings.controllertype].controllerunitstr);
+{$endif ARM}
+ end;
+
+
+ procedure loadautounits;
+ var
+ hs,s : string;
+ begin
+ hs:=autoloadunits;
+ repeat
+ s:=GetToken(hs,',');
+ if s='' then
+ break;
+ AddUnit(s);
+ until false;
+ end;
+
+
+ procedure loadunits;
+ var
+ s,sorg : ansistring;
+ fn : string;
+ pu : tused_unit;
+ hp2 : tmodule;
+ unitsym : tunitsym;
+ begin
+ consume(_USES);
+ repeat
+ s:=pattern;
+ sorg:=orgpattern;
+ consume(_ID);
+ while token=_POINT do
+ begin
+ consume(_POINT);
+ s:=s+'.'+pattern;
+ sorg:=sorg+'.'+orgpattern;
+ consume(_ID);
+ end;
+ { support "<unit> in '<file>'" construct, but not for tp7 }
+ fn:='';
+ if not(m_tp7 in current_settings.modeswitches) and
+ try_to_consume(_OP_IN) then
+ fn:=FixFileName(get_stringconst);
+ { Give a warning if lineinfo is loaded }
+ if s='LINEINFO' then begin
+ Message(parser_w_no_lineinfo_use_switch);
+ if (paratargetdbg in [dbg_dwarf2, dbg_dwarf3]) then
+ s := 'LNFODWRF';
+ sorg := s;
+ end;
+ { Give a warning if objpas is loaded }
+ if s='OBJPAS' then
+ Message(parser_w_no_objpas_use_mode);
+ { Using the unit itself is not possible }
+ if (s<>current_module.modulename^) then
+ begin
+ { check if the unit is already used }
+ hp2:=nil;
+ pu:=tused_unit(current_module.used_units.first);
+ while assigned(pu) do
+ begin
+ if (pu.u.modulename^=s) then
+ begin
+ hp2:=pu.u;
+ break;
+ end;
+ pu:=tused_unit(pu.next);
+ end;
+ if not assigned(hp2) then
+ hp2:=registerunit(current_module,sorg,fn)
+ else
+ Message1(sym_e_duplicate_id,s);
+ { Create unitsym, we need to use the name as specified, we
+ can not use the modulename because that can be different
+ when -Un is used }
+ unitsym:=tunitsym.create(sorg,nil);
+ tabstractunitsymtable(current_module.localsymtable).insertunit(unitsym);
+ { the current module uses the unit hp2 }
+ current_module.addusedunit(hp2,true,unitsym);
+ end
+ else
+ Message1(sym_e_duplicate_id,s);
+ if token=_COMMA then
+ begin
+ pattern:='';
+ consume(_COMMA);
+ end
+ else
+ break;
+ until false;
+
+ { Load the units }
+ pu:=tused_unit(current_module.used_units.first);
+ while assigned(pu) do
+ begin
+ { Only load the units that are in the current
+ (interface/implementation) uses clause }
+ if pu.in_uses and
+ (pu.in_interface=current_module.in_interface) then
+ begin
+ tppumodule(pu.u).loadppu;
+ { is our module compiled? then we can stop }
+ if current_module.state=ms_compiled then
+ exit;
+ { add this unit to the dependencies }
+ pu.u.adddependency(current_module);
+ { save crc values }
+ pu.checksum:=pu.u.crc;
+ pu.interface_checksum:=pu.u.interface_crc;
+ pu.indirect_checksum:=pu.u.indirect_crc;
+ { connect unitsym to the module }
+ pu.unitsym.module:=pu.u;
+ { add to symtable stack }
+ symtablestack.push(pu.u.globalsymtable);
+ if (m_mac in current_settings.modeswitches) and
+ assigned(pu.u.globalmacrosymtable) then
+ macrosymtablestack.push(pu.u.globalmacrosymtable);
+ { check hints }
+ pu.u.check_hints;
+ end;
+ pu:=tused_unit(pu.next);
+ end;
+
+ consume(_SEMICOLON);
+ end;
+
+
+ procedure reset_all_defs;
+ begin
+ if assigned(current_module.wpoinfo) then
+ current_module.wpoinfo.resetdefs;
+ end;
+
+
+ procedure free_localsymtables(st:TSymtable);
+ var
+ i : longint;
+ def : tstoreddef;
+ pd : tprocdef;
+ begin
+ for i:=0 to st.DefList.Count-1 do
+ begin
+ def:=tstoreddef(st.DefList[i]);
+ if def.typ=procdef then
+ begin
+ pd:=tprocdef(def);
+ if assigned(pd.localst) and
+ (pd.localst.symtabletype<>staticsymtable) and
+ not(po_inline in pd.procoptions) then
+ begin
+ free_localsymtables(pd.localst);
+ pd.localst.free;
+ pd.localst:=nil;
+ end;
+ end;
+ end;
+ end;
+
+
+ procedure parse_implementation_uses;
+ begin
+ if token=_USES then
+ loadunits;
+ end;
+
+
+ procedure setupglobalswitches;
+ begin
+ if (cs_create_pic in current_settings.moduleswitches) then
+ begin
+ def_system_macro('FPC_PIC');
+ def_system_macro('PIC');
+ end;
+ end;
+
+
+ function create_main_proc(const name:string;potype:tproctypeoption;st:TSymtable):tcgprocinfo;
+ var
+ ps : tprocsym;
+ pd : tprocdef;
+ begin
+ { there should be no current_procinfo available }
+ if assigned(current_procinfo) then
+ internalerror(200304275);
+ {Generate a procsym for main}
+ ps:=tprocsym.create('$'+name);
+ { main are allways used }
+ inc(ps.refs);
+ st.insert(ps);
+ pd:=tprocdef.create(main_program_level);
+ include(pd.procoptions,po_global);
+ pd.procsym:=ps;
+ ps.ProcdefList.Add(pd);
+ { set procdef options }
+ pd.proctypeoption:=potype;
+ pd.proccalloption:=pocall_default;
+ include(pd.procoptions,po_hascallingconvention);
+ pd.forwarddef:=false;
+ pd.setmangledname(target_info.cprefix+name);
+ pd.aliasnames.insert(pd.mangledname);
+ handle_calling_convention(pd);
+ { We don't need is a local symtable. Change it into the static
+ symtable }
+ pd.localst.free;
+ pd.localst:=st;
+ { set procinfo and current_procinfo.procdef }
+ result:=tcgprocinfo(cprocinfo.create(nil));
+ result.procdef:=pd;
+ { main proc does always a call e.g. to init system unit }
+ include(result.flags,pi_do_call);
+ end;
+
+
+ procedure release_main_proc(pi:tcgprocinfo);
+ begin
+ { remove localst as it was replaced by staticsymtable }
+ pi.procdef.localst:=nil;
+ { remove procinfo }
+ current_module.procinfo:=nil;
+ pi.free;
+ pi:=nil;
+ end;
+
+
+
+ { Insert _GLOBAL_OFFSET_TABLE_ symbol if system uses it }
+
+ procedure maybe_load_got;
+{$ifdef i386}
+ var
+ gotvarsym : tstaticvarsym;
+{$endif i386}
+ begin
+{$ifdef i386}
+ if (cs_create_pic in current_settings.moduleswitches) and
+ (tf_pic_uses_got in target_info.flags) then
+ begin
+ { insert symbol for got access in assembler code}
+ gotvarsym:=tstaticvarsym.create('_GLOBAL_OFFSET_TABLE_',
+ vs_value,voidpointertype,[vo_is_external]);
+ gotvarsym.set_mangledname('_GLOBAL_OFFSET_TABLE_');
+ current_module.localsymtable.insert(gotvarsym);
+ { avoid unnecessary warnings }
+ gotvarsym.varstate:=vs_read;
+ gotvarsym.refs:=1;
+ end;
+{$endif i386}
+ end;
+
+ function gen_implicit_initfinal(flag:word;st:TSymtable):tcgprocinfo;
+ begin
+ { create procdef }
+ case flag of
+ uf_init :
+ begin
+ result:=create_main_proc(make_mangledname('',current_module.localsymtable,'init_implicit'),potype_unitinit,st);
+ result.procdef.aliasnames.insert(make_mangledname('INIT$',current_module.localsymtable,''));
+ end;
+ uf_finalize :
+ begin
+ result:=create_main_proc(make_mangledname('',current_module.localsymtable,'finalize_implicit'),potype_unitfinalize,st);
+ result.procdef.aliasnames.insert(make_mangledname('FINALIZE$',current_module.localsymtable,''));
+ if (not current_module.is_unit) then
+ result.procdef.aliasnames.insert('PASCALFINALIZE');
+ end;
+ else
+ internalerror(200304253);
+ end;
+ result.code:=cnothingnode.create;
+ end;
+
+
+ procedure copy_macro(p:TObject; arg:pointer);
+ begin
+ current_module.globalmacrosymtable.insert(tmacro(p).getcopy);
+ end;
+
+ function try_consume_hintdirective(var moduleopt:tmoduleoptions; var deprecatedmsg:pshortstring):boolean;
+ var
+ last_is_deprecated:boolean;
+ begin
+ try_consume_hintdirective:=false;
+ repeat
+ last_is_deprecated:=false;
+ case idtoken of
+ _LIBRARY :
+ begin
+ include(moduleopt,mo_hint_library);
+ try_consume_hintdirective:=true;
+ end;
+ _DEPRECATED :
+ begin
+ include(moduleopt,mo_hint_deprecated);
+ try_consume_hintdirective:=true;
+ last_is_deprecated:=true;
+ end;
+ _EXPERIMENTAL :
+ begin
+ include(moduleopt,mo_hint_experimental);
+ try_consume_hintdirective:=true;
+ end;
+ _PLATFORM :
+ begin
+ include(moduleopt,mo_hint_platform);
+ try_consume_hintdirective:=true;
+ end;
+ _UNIMPLEMENTED :
+ begin
+ include(moduleopt,mo_hint_unimplemented);
+ try_consume_hintdirective:=true;
+ end;
+ else
+ break;
+ end;
+ consume(Token);
+ { handle deprecated message }
+ if ((token=_CSTRING) or (token=_CCHAR)) and last_is_deprecated then
+ begin
+ if deprecatedmsg<>nil then
+ internalerror(201001221);
+ if token=_CSTRING then
+ deprecatedmsg:=stringdup(cstringpattern)
+ else
+ deprecatedmsg:=stringdup(pattern);
+ consume(token);
+ include(moduleopt,mo_has_deprecated_msg);
+ end;
+ until false;
+ end;
+
+ procedure proc_unit;
+
+ function is_assembler_generated:boolean;
+ var
+ hal : tasmlisttype;
+ begin
+ result:=false;
+ if Errorcount=0 then
+ begin
+ for hal:=low(TasmlistType) to high(TasmlistType) do
+ if not current_asmdata.asmlists[hal].empty then
+ begin
+ result:=true;
+ exit;
+ end;
+ end;
+ end;
+
+ var
+ main_file: tinputfile;
+{$ifdef EXTDEBUG}
+ store_crc,
+{$endif EXTDEBUG}
+ store_interface_crc,
+ store_indirect_crc: cardinal;
+ s1,s2 : ^string; {Saves stack space}
+ force_init_final : boolean;
+ init_procinfo,
+ finalize_procinfo : tcgprocinfo;
+ unitname : ansistring;
+ unitname8 : string[8];
+ ag: boolean;
+{$ifdef debug_devirt}
+ i: longint;
+{$endif debug_devirt}
+ begin
+ init_procinfo:=nil;
+ finalize_procinfo:=nil;
+
+ if m_mac in current_settings.modeswitches then
+ current_module.mode_switch_allowed:= false;
+
+ consume(_UNIT);
+ if compile_level=1 then
+ Status.IsExe:=false;
+
+ unitname:=orgpattern;
+ consume(_ID);
+ while token=_POINT do
+ begin
+ consume(_POINT);
+ unitname:=unitname+'.'+orgpattern;
+ consume(_ID);
+ end;
+
+ { create filenames and unit name }
+ main_file := current_scanner.inputfile;
+ while assigned(main_file.next) do
+ main_file := main_file.next;
+
+ new(s1);
+ s1^:=current_module.modulename^;
+ current_module.SetFileName(main_file.path^+main_file.name^,true);
+ current_module.SetModuleName(unitname);
+
+ { check for system unit }
+ new(s2);
+ s2^:=upper(ChangeFileExt(ExtractFileName(main_file.name^),''));
+ unitname8:=copy(current_module.modulename^,1,8);
+ if (cs_check_unit_name in current_settings.globalswitches) and
+ (
+ not(
+ (current_module.modulename^=s2^) or
+ (
+ (length(current_module.modulename^)>8) and
+ (unitname8=s2^)
+ )
+ )
+ or
+ (
+ (length(s1^)>8) and
+ (s1^<>current_module.modulename^)
+ )
+ ) then
+ Message1(unit_e_illegal_unit_name,current_module.realmodulename^);
+ if (current_module.modulename^='SYSTEM') then
+ include(current_settings.moduleswitches,cs_compilesystem);
+ dispose(s2);
+ dispose(s1);
+
+ if (target_info.system in systems_unit_program_exports) then
+ exportlib.preparelib(current_module.realmodulename^);
+
+ { parse hint directives }
+ try_consume_hintdirective(current_module.moduleoptions, current_module.deprecatedmsg);
+
+ consume(_SEMICOLON);
+ consume(_INTERFACE);
+ { global switches are read, so further changes aren't allowed }
+ current_module.in_global:=false;
+
+ { handle the global switches }
+ setupglobalswitches;
+
+ message1(unit_u_loading_interface_units,current_module.modulename^);
+
+ { update status }
+ status.currentmodule:=current_module.realmodulename^;
+
+ { maybe turn off m_objpas if we are compiling objpas }
+ if (current_module.modulename^='OBJPAS') then
+ exclude(current_settings.modeswitches,m_objpas);
+
+ { maybe turn off m_mac if we are compiling macpas }
+ if (current_module.modulename^='MACPAS') then
+ exclude(current_settings.modeswitches,m_mac);
+
+ parse_only:=true;
+
+ { generate now the global symboltable,
+ define first as local to overcome dependency conflicts }
+ current_module.localsymtable:=tglobalsymtable.create(current_module.modulename^,current_module.moduleid);
+
+ { insert unitsym of this unit to prevent other units having
+ the same name }
+ tabstractunitsymtable(current_module.localsymtable).insertunit(tunitsym.create(current_module.realmodulename^,current_module));
+
+ { load default units, like the system unit }
+ loaddefaultunits;
+
+ { insert qualifier for the system unit (allows system.writeln) }
+ if not(cs_compilesystem in current_settings.moduleswitches) and
+ (token=_USES) then
+ begin
+ loadunits;
+ { has it been compiled at a higher level ?}
+ if current_module.state=ms_compiled then
+ exit;
+ end;
+
+ { move the global symtable from the temporary local to global }
+ current_module.globalsymtable:=current_module.localsymtable;
+ current_module.localsymtable:=nil;
+
+ { number all units, so we know if a unit is used by this unit or
+ needs to be added implicitly }
+ current_module.updatemaps;
+
+ { create whole program optimisation information (may already be
+ updated in the interface, e.g., in case of classrefdef typed
+ constants }
+ current_module.wpoinfo:=tunitwpoinfo.create;
+
+ { ... parse the declarations }
+ Message1(parser_u_parsing_interface,current_module.realmodulename^);
+ symtablestack.push(current_module.globalsymtable);
+ read_interface_declarations;
+ symtablestack.pop(current_module.globalsymtable);
+
+ { Export macros defined in the interface for macpas. The macros
+ are put in the globalmacrosymtable that will only be used by other
+ units. The current unit continues to use the localmacrosymtable }
+ if (m_mac in current_settings.modeswitches) then
+ begin
+ current_module.globalmacrosymtable:=tmacrosymtable.create(true);
+ current_module.localmacrosymtable.SymList.ForEachCall(@copy_macro,nil);
+ end;
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+ { Our interface is compiled, generate CRC and switch to implementation }
+ if not(cs_compilesystem in current_settings.moduleswitches) and
+ (Errorcount=0) then
+ tppumodule(current_module).getppucrc;
+ current_module.in_interface:=false;
+ current_module.interface_compiled:=true;
+
+ { First reload all units depending on our interface, we need to do this
+ in the implementation part to prevent erroneous circular references }
+ tppumodule(current_module).setdefgeneration;
+ tppumodule(current_module).reload_flagged_units;
+
+ { Parse the implementation section }
+ if (m_mac in current_settings.modeswitches) and try_to_consume(_END) then
+ current_module.interface_only:=true
+ else
+ current_module.interface_only:=false;
+
+ parse_only:=false;
+
+ { create static symbol table }
+ current_module.localsymtable:=tstaticsymtable.create(current_module.modulename^,current_module.moduleid);
+
+ { Insert _GLOBAL_OFFSET_TABLE_ symbol if system uses it }
+ maybe_load_got;
+
+ if not current_module.interface_only then
+ begin
+ consume(_IMPLEMENTATION);
+ Message1(unit_u_loading_implementation_units,current_module.modulename^);
+ { Read the implementation units }
+ parse_implementation_uses;
+ end;
+
+ if current_module.state=ms_compiled then
+ exit;
+
+ { All units are read, now give them a number }
+ current_module.updatemaps;
+
+ symtablestack.push(current_module.globalsymtable);
+ symtablestack.push(current_module.localsymtable);
+
+ if not current_module.interface_only then
+ begin
+ Message1(parser_u_parsing_implementation,current_module.modulename^);
+ if current_module.in_interface then
+ internalerror(200212285);
+
+ { Compile the unit }
+ init_procinfo:=create_main_proc(make_mangledname('',current_module.localsymtable,'init'),potype_unitinit,current_module.localsymtable);
+ init_procinfo.procdef.aliasnames.insert(make_mangledname('INIT$',current_module.localsymtable,''));
+ init_procinfo.parse_body;
+ { save file pos for debuginfo }
+ current_module.mainfilepos:=init_procinfo.entrypos;
+ end;
+
+ { Generate specializations of objectdefs methods }
+ generate_specialization_procs;
+
+ { if the unit contains ansi/widestrings, initialization and
+ finalization code must be forced }
+ force_init_final:=tglobalsymtable(current_module.globalsymtable).needs_init_final or
+ tstaticsymtable(current_module.localsymtable).needs_init_final;
+
+ { should we force unit initialization? }
+ { this is a hack, but how can it be done better ? }
+ { Now the sole purpose of this is to change 'init' to 'init_implicit', is it needed at all? (Sergei) }
+ if force_init_final and assigned(init_procinfo) and has_no_code(init_procinfo.code) then
+ begin
+ { first release the not used init procinfo }
+ if assigned(init_procinfo) then
+ release_main_proc(init_procinfo);
+ init_procinfo:=gen_implicit_initfinal(uf_init,current_module.localsymtable);
+ end;
+ { finalize? }
+ if not current_module.interface_only and (token=_FINALIZATION) then
+ begin
+ { Compile the finalize }
+ finalize_procinfo:=create_main_proc(make_mangledname('',current_module.localsymtable,'finalize'),potype_unitfinalize,current_module.localsymtable);
+ finalize_procinfo.procdef.aliasnames.insert(make_mangledname('FINALIZE$',current_module.localsymtable,''));
+ finalize_procinfo.parse_body;
+ end
+ else if force_init_final then
+ finalize_procinfo:=gen_implicit_initfinal(uf_finalize,current_module.localsymtable);
+
+ { Now both init and finalize bodies are read and it is known
+ which variables are used in both init and finalize we can now
+ generate the code. This is required to prevent putting a variable in
+ a register that is also used in the finalize body (PFV) }
+ if assigned(init_procinfo) then
+ begin
+ if force_init_final or not(has_no_code(init_procinfo.code)) then
+ begin
+ init_procinfo.generate_code;
+ current_module.flags:=current_module.flags or uf_init;
+ end;
+ init_procinfo.resetprocdef;
+ release_main_proc(init_procinfo);
+ end;
+ if assigned(finalize_procinfo) then
+ begin
+ if force_init_final or not(has_no_code(finalize_procinfo.code)) then
+ begin
+ finalize_procinfo.generate_code;
+ current_module.flags:=current_module.flags or uf_finalize;
+ end;
+ finalize_procinfo.resetprocdef;
+ release_main_proc(finalize_procinfo);
+ end;
+
+ symtablestack.pop(current_module.localsymtable);
+ symtablestack.pop(current_module.globalsymtable);
+
+ { the last char should always be a point }
+ consume(_POINT);
+
+ { reset wpo flags for all defs }
+ reset_all_defs;
+
+ if (Errorcount=0) then
+ begin
+ { tests, if all (interface) forwards are resolved }
+ tstoredsymtable(current_module.globalsymtable).check_forwards;
+ { check if all private fields are used }
+ tstoredsymtable(current_module.globalsymtable).allprivatesused;
+
+ { test static symtable }
+ tstoredsymtable(current_module.localsymtable).allsymbolsused;
+ tstoredsymtable(current_module.localsymtable).allprivatesused;
+ tstoredsymtable(current_module.localsymtable).check_forwards;
+ tstoredsymtable(current_module.localsymtable).checklabels;
+
+ { used units }
+ current_module.allunitsused;
+ end;
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+ { if an Objective-C module, generate rtti and module info }
+ MaybeGenerateObjectiveCImageInfo(current_module.globalsymtable,current_module.localsymtable);
+
+ { do we need to add the variants unit? }
+ maybeloadvariantsunit;
+
+ { generate wrappers for interfaces }
+ gen_intf_wrappers(current_asmdata.asmlists[al_procedures],current_module.globalsymtable,false);
+ gen_intf_wrappers(current_asmdata.asmlists[al_procedures],current_module.localsymtable,false);
+
+ { generate rtti/init tables }
+ write_persistent_type_info(current_module.globalsymtable);
+ write_persistent_type_info(current_module.localsymtable);
+
+ { Tables }
+ InsertThreadvars;
+
+ { Resource strings }
+ GenerateResourceStrings;
+
+ { Widestring typed constants }
+ InsertWideInits;
+
+ { Resourcestring references }
+ InsertResStrInits;
+
+ { generate debuginfo }
+ if (cs_debuginfo in current_settings.moduleswitches) then
+ current_debuginfo.inserttypeinfo;
+
+ { generate imports }
+ if current_module.ImportLibraryList.Count>0 then
+ importlib.generatelib;
+
+ { insert own objectfile, or say that it's in a library
+ (no check for an .o when loading) }
+ ag:=is_assembler_generated;
+ if ag then
+ insertobjectfile
+ else
+ begin
+ current_module.flags:=current_module.flags or uf_no_link;
+ current_module.flags:=current_module.flags and not (uf_has_stabs_debuginfo or uf_has_dwarf_debuginfo);
+ end;
+
+ if ag then
+ begin
+ { create callframe info }
+ create_dwarf_frame;
+ { assemble }
+ create_objectfile;
+ end;
+
+ { Write out the ppufile after the object file has been created }
+ store_interface_crc:=current_module.interface_crc;
+ store_indirect_crc:=current_module.indirect_crc;
+{$ifdef EXTDEBUG}
+ store_crc:=current_module.crc;
+{$endif EXTDEBUG}
+ if (Errorcount=0) then
+ tppumodule(current_module).writeppu;
+
+ if not(cs_compilesystem in current_settings.moduleswitches) then
+ begin
+ if store_interface_crc<>current_module.interface_crc then
+ Message1(unit_u_interface_crc_changed,current_module.ppufilename^);
+ if store_indirect_crc<>current_module.indirect_crc then
+ Message1(unit_u_indirect_crc_changed,current_module.ppufilename^);
+ end;
+{$ifdef EXTDEBUG}
+ if not(cs_compilesystem in current_settings.moduleswitches) then
+ if (store_crc<>current_module.crc) and simplify_ppu then
+ Message1(unit_u_implementation_crc_changed,current_module.ppufilename^);
+{$endif EXTDEBUG}
+
+ { release local symtables that are not needed anymore }
+ free_localsymtables(current_module.globalsymtable);
+ free_localsymtables(current_module.localsymtable);
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+{$ifdef debug_devirt}
+ { print out all instantiated class/object types }
+ writeln('constructed object/class/classreftypes in ',current_module.realmodulename^);
+ for i := 0 to current_module.wpoinfo.createdobjtypes.count-1 do
+ begin
+ write(' ',tdef(current_module.wpoinfo.createdobjtypes[i]).GetTypeName);
+ case tdef(current_module.wpoinfo.createdobjtypes[i]).typ of
+ objectdef:
+ case tobjectdef(current_module.wpoinfo.createdobjtypes[i]).objecttype of
+ odt_object:
+ writeln(' (object)');
+ odt_class:
+ writeln(' (class)');
+ else
+ internalerror(2008101103);
+ end;
+ else
+ internalerror(2008101104);
+ end;
+ end;
+
+ for i := 0 to current_module.wpoinfo.createdclassrefobjtypes.count-1 do
+ begin
+ write(' Class Of ',tdef(current_module.wpoinfo.createdclassrefobjtypes[i]).GetTypeName);
+ case tdef(current_module.wpoinfo.createdclassrefobjtypes[i]).typ of
+ objectdef:
+ case tobjectdef(current_module.wpoinfo.createdclassrefobjtypes[i]).objecttype of
+ odt_class:
+ writeln(' (classrefdef)');
+ else
+ internalerror(2008101105);
+ end
+ else
+ internalerror(2008101102);
+ end;
+ end;
+{$endif debug_devirt}
+
+ Message1(unit_u_finished_compiling,current_module.modulename^);
+ end;
+
+
+ procedure procexport(const s : string);
+ var
+ hp : texported_item;
+ begin
+ hp:=texported_item.create;
+ hp.name:=stringdup(s);
+ hp.options:=hp.options or eo_name;
+ exportlib.exportprocedure(hp);
+ end;
+
+
+ procedure varexport(const s : string);
+ var
+ hp : texported_item;
+ begin
+ hp:=texported_item.create;
+ hp.name:=stringdup(s);
+ hp.options:=hp.options or eo_name;
+ exportlib.exportvar(hp);
+ end;
+
+
+ procedure insert_export(sym : TObject;arg:pointer);
+ var
+ i : longint;
+ item : TCmdStrListItem;
+ begin
+ case TSym(sym).typ of
+ { ignore: }
+ unitsym,
+ syssym,
+ constsym,
+ enumsym,
+ typesym:
+ ;
+ procsym:
+ begin
+ for i:=0 to tprocsym(sym).ProcdefList.Count-1 do
+ begin
+ if not(tprocdef(tprocsym(sym).ProcdefList[i]).proccalloption in [pocall_internproc]) and
+ ((tprocdef(tprocsym(sym).ProcdefList[i]).procoptions*[po_external])=[]) and
+ ((tsymtable(arg).symtabletype=globalsymtable) or
+ ((tsymtable(arg).symtabletype=staticsymtable) and (po_public in tprocdef(tprocsym(sym).ProcdefList[i]).procoptions))
+ ) then
+ begin
+ procexport(tprocdef(tprocsym(sym).ProcdefList[i]).mangledname);
+ { walk through all aliases }
+ item:=TCmdStrListItem(tprocdef(tprocsym(sym).ProcdefList[i]).aliasnames.first);
+ while assigned(item) do
+ begin
+ { avoid duplicate entries, sometimes aliasnames contains the mangledname }
+ if item.str<>tprocdef(tprocsym(sym).ProcdefList[i]).mangledname then
+ procexport(item.str);
+ item:=TCmdStrListItem(item.next);
+ end;
+ end;
+ end;
+ end;
+ staticvarsym:
+ begin
+ varexport(tsym(sym).mangledname);
+ end;
+ else
+ begin
+ writeln('unknown: ',ord(TSym(sym).typ));
+ end;
+ end;
+ end;
+
+
+ Function RewritePPU(const PPUFn,PPLFn:String):Boolean;
+ Var
+ MakeStatic : Boolean;
+ Var
+ buffer : array[0..$1fff] of byte;
+ inppu,
+ outppu : tppufile;
+ b,
+ untilb : byte;
+ l,m : longint;
+ f : file;
+ ext,
+ s : string;
+ ppuversion : dword;
+ begin
+ Result:=false;
+ MakeStatic:=False;
+ inppu:=tppufile.create(PPUFn);
+ if not inppu.openfile then
+ begin
+ inppu.free;
+ Comment(V_Error,'Could not open : '+PPUFn);
+ Exit;
+ end;
+ { Check the ppufile }
+ if not inppu.CheckPPUId then
+ begin
+ inppu.free;
+ Comment(V_Error,'Not a PPU File : '+PPUFn);
+ Exit;
+ end;
+ ppuversion:=inppu.GetPPUVersion;
+ if ppuversion<CurrentPPUVersion then
+ begin
+ inppu.free;
+ Comment(V_Error,'Wrong PPU Version '+tostr(ppuversion)+' in '+PPUFn);
+ Exit;
+ end;
+ { No .o file generated for this ppu, just skip }
+ if (inppu.header.flags and uf_no_link)<>0 then
+ begin
+ inppu.free;
+ Result:=true;
+ Exit;
+ end;
+ { Already a lib? }
+ if (inppu.header.flags and uf_in_library)<>0 then
+ begin
+ inppu.free;
+ Comment(V_Error,'PPU is already in a library : '+PPUFn);
+ Exit;
+ end;
+ { We need a static linked unit }
+ if (inppu.header.flags and uf_static_linked)=0 then
+ begin
+ inppu.free;
+ Comment(V_Error,'PPU is not static linked : '+PPUFn);
+ Exit;
+ end;
+ { Check if shared is allowed }
+ if tsystem(inppu.header.target) in [system_i386_go32v2] then
+ begin
+ Comment(V_Error,'Shared library not supported for ppu target, switching to static library');
+ MakeStatic:=true;
+ end;
+ { Create the new ppu }
+ if PPUFn=PPLFn then
+ outppu:=tppufile.create('ppumove.$$$')
+ else
+ outppu:=tppufile.create(PPLFn);
+ outppu.createfile;
+ { Create new header, with the new flags }
+ outppu.header:=inppu.header;
+ outppu.header.flags:=outppu.header.flags or uf_in_library;
+ if MakeStatic then
+ outppu.header.flags:=outppu.header.flags or uf_static_linked
+ else
+ outppu.header.flags:=outppu.header.flags or uf_shared_linked;
+ { read until the object files are found }
+ untilb:=iblinkunitofiles;
+ repeat
+ b:=inppu.readentry;
+ if b in [ibendinterface,ibend] then
+ begin
+ inppu.free;
+ outppu.free;
+ Comment(V_Error,'No files to be linked found : '+PPUFn);
+ Exit;
+ end;
+ if b<>untilb then
+ begin
+ repeat
+ inppu.getdatabuf(buffer,sizeof(buffer),l);
+ outppu.putdata(buffer,l);
+ until l<sizeof(buffer);
+ outppu.writeentry(b);
+ end;
+ until (b=untilb);
+ { we have now reached the section for the files which need to be added,
+ now add them to the list }
+ case b of
+ iblinkunitofiles :
+ begin
+ { add all o files, and save the entry when not creating a static
+ library to keep staticlinking possible }
+ while not inppu.endofentry do
+ begin
+ s:=inppu.getstring;
+ m:=inppu.getlongint;
+ if not MakeStatic then
+ begin
+ outppu.putstring(s);
+ outppu.putlongint(m);
+ end;
+ current_module.linkotherofiles.add(s,link_always);;
+ end;
+ if not MakeStatic then
+ outppu.writeentry(b);
+ end;
+ { iblinkunitstaticlibs :
+ begin
+ AddToLinkFiles(ExtractLib(inppu.getstring));
+ if not inppu.endofentry then
+ begin
+ repeat
+ inppu.getdatabuf(buffer^,bufsize,l);
+ outppu.putdata(buffer^,l);
+ until l<bufsize;
+ outppu.writeentry(b);
+ end;
+ end; }
+ end;
+ { just add a new entry with the new lib }
+ if MakeStatic then
+ begin
+ outppu.putstring('imp'+current_module.realmodulename^);
+ outppu.putlongint(link_static);
+ outppu.writeentry(iblinkunitstaticlibs)
+ end
+ else
+ begin
+ outppu.putstring('imp'+current_module.realmodulename^);
+ outppu.putlongint(link_shared);
+ outppu.writeentry(iblinkunitsharedlibs);
+ end;
+ { read all entries until the end and write them also to the new ppu }
+ repeat
+ b:=inppu.readentry;
+ { don't write ibend, that's written automatically }
+ if b<>ibend then
+ begin
+ if b=iblinkothersharedlibs then
+ begin
+ while not inppu.endofentry do
+ begin
+ s:=inppu.getstring;
+ m:=inppu.getlongint;
+
+ outppu.putstring(s);
+ outppu.putlongint(m);
+
+ { strip lib prefix }
+ if copy(s,1,3)='lib' then
+ delete(s,1,3);
+ ext:=ExtractFileExt(s);
+ if ext<>'' then
+ delete(s,length(s)-length(ext)+1,length(ext));
+
+ current_module.linkOtherSharedLibs.add(s,link_always);
+ end;
+ end
+ else
+ repeat
+ inppu.getdatabuf(buffer,sizeof(buffer),l);
+ outppu.putdata(buffer,l);
+ until l<sizeof(buffer);
+ outppu.writeentry(b);
+ end;
+ until b=ibend;
+ { write the last stuff and close }
+ outppu.flush;
+ outppu.writeheader;
+ outppu.free;
+ inppu.free;
+ { rename }
+ if PPUFn=PPLFn then
+ begin
+ {$push}{$I-}
+ assign(f,PPUFn);
+ erase(f);
+ assign(f,'ppumove.$$$');
+ rename(f,PPUFn);
+ {$pop}
+ if ioresult<>0 then;
+ end;
+ Result:=True;
+ end;
+
+
+ procedure createimportlibfromexports;
+ var
+ hp : texported_item;
+ begin
+ hp:=texported_item(current_module._exports.first);
+ while assigned(hp) do
+ begin
+ current_module.AddExternalImport(current_module.realmodulename^,hp.name^,hp.name^,hp.index,hp.is_var,false);
+ hp:=texported_item(hp.next);
+ end;
+ end;
+
+
+ procedure proc_package;
+ var
+ main_file : tinputfile;
+ hp,hp2 : tmodule;
+ {finalize_procinfo,
+ init_procinfo,
+ main_procinfo : tcgprocinfo;}
+ force_init_final : boolean;
+ uu : tused_unit;
+ module_name: ansistring;
+ begin
+ Status.IsPackage:=true;
+ Status.IsExe:=true;
+ parse_only:=false;
+ {main_procinfo:=nil;
+ init_procinfo:=nil;
+ finalize_procinfo:=nil;}
+
+ if not RelocSectionSetExplicitly then
+ RelocSection:=true;
+
+ { Relocation works only without stabs under Windows when }
+ { external linker (LD) is used. LD generates relocs for }
+ { stab sections which is not loaded in memory. It causes }
+ { AV error when DLL is loaded and relocation is needed. }
+ { Internal linker does not have this problem. }
+ if RelocSection and
+ (target_info.system in systems_all_windows+[system_i386_wdosx]) and
+ (cs_link_extern in current_settings.globalswitches) then
+ begin
+ include(current_settings.globalswitches,cs_link_strip);
+ { Warning stabs info does not work with reloc section !! }
+ if (cs_debuginfo in current_settings.moduleswitches) and
+ (target_dbg.id=dbg_stabs) then
+ begin
+ Message1(parser_w_parser_reloc_no_debug,current_module.mainsource^);
+ Message(parser_w_parser_win32_debug_needs_WN);
+ exclude(current_settings.moduleswitches,cs_debuginfo);
+ end;
+ end;
+ { get correct output names }
+ main_file := current_scanner.inputfile;
+ while assigned(main_file.next) do
+ main_file := main_file.next;
+
+ current_module.SetFileName(main_file.path^+main_file.name^,true);
+
+ { consume _PACKAGE word }
+ consume(_ID);
+
+ module_name:=orgpattern;
+ consume(_ID);
+ while token=_POINT do
+ begin
+ consume(_POINT);
+ module_name:=module_name+'.'+orgpattern;
+ consume(_ID);
+ end;
+
+ current_module.setmodulename(module_name);
+ current_module.ispackage:=true;
+ exportlib.preparelib(module_name);
+
+ if tf_library_needs_pic in target_info.flags then
+ include(current_settings.moduleswitches,cs_create_pic);
+
+ consume(_SEMICOLON);
+
+ { global switches are read, so further changes aren't allowed }
+ current_module.in_global:=false;
+
+ { setup things using the switches }
+ setupglobalswitches;
+
+ { set implementation flag }
+ current_module.in_interface:=false;
+ current_module.interface_compiled:=true;
+
+ { insert after the unit symbol tables the static symbol table }
+ { of the program }
+ current_module.localsymtable:=tstaticsymtable.create(current_module.modulename^,current_module.moduleid);
+
+ {Load the units used by the program we compile.}
+ if token=_REQUIRES then
+ begin
+ end;
+
+ {Load the units used by the program we compile.}
+ if (token=_ID) and (idtoken=_CONTAINS) then
+ begin
+ { consume _CONTAINS word }
+ consume(_ID);
+ while true do
+ begin
+ if token=_ID then
+ begin
+ module_name:=pattern;
+ consume(_ID);
+ while token=_POINT do
+ begin
+ consume(_POINT);
+ module_name:=module_name+'.'+orgpattern;
+ consume(_ID);
+ end;
+ AddUnit(module_name);
+ end
+ else
+ consume(_ID);
+ if token=_COMMA then
+ consume(_COMMA)
+ else break;
+ end;
+ consume(_SEMICOLON);
+ end;
+
+ { All units are read, now give them a number }
+ current_module.updatemaps;
+
+ {Insert the name of the main program into the symbol table.}
+ if current_module.realmodulename^<>'' then
+ tabstractunitsymtable(current_module.localsymtable).insertunit(tunitsym.create(current_module.realmodulename^,current_module));
+
+ Message1(parser_u_parsing_implementation,current_module.mainsource^);
+
+ symtablestack.push(current_module.localsymtable);
+
+ { create whole program optimisation information }
+ current_module.wpoinfo:=tunitwpoinfo.create;
+
+ { should we force unit initialization? }
+ force_init_final:=tstaticsymtable(current_module.localsymtable).needs_init_final;
+ if force_init_final then
+ {init_procinfo:=gen_implicit_initfinal(uf_init,current_module.localsymtable)};
+
+ { Add symbol to the exports section for win32 so smartlinking a
+ DLL will include the edata section }
+ if assigned(exportlib) and
+ (target_info.system in [system_i386_win32,system_i386_wdosx]) and
+ ((current_module.flags and uf_has_exports)<>0) then
+ current_asmdata.asmlists[al_procedures].concat(tai_const.createname(make_mangledname('EDATA',current_module.localsymtable,''),0));
+
+ { all labels must be defined before generating code }
+ if Errorcount=0 then
+ tstoredsymtable(current_module.localsymtable).checklabels;
+
+ symtablestack.pop(current_module.localsymtable);
+
+ { consume the last point }
+ consume(_END);
+ consume(_POINT);
+
+ if (Errorcount=0) then
+ begin
+ { test static symtable }
+ tstoredsymtable(current_module.localsymtable).allsymbolsused;
+ tstoredsymtable(current_module.localsymtable).allprivatesused;
+ tstoredsymtable(current_module.localsymtable).check_forwards;
+
+ current_module.allunitsused;
+ end;
+
+ new_section(current_asmdata.asmlists[al_globals],sec_data,'_FPCDummy',4);
+ current_asmdata.asmlists[al_globals].concat(tai_symbol.createname_global('_FPCDummy',AT_DATA,0));
+ current_asmdata.asmlists[al_globals].concat(tai_const.create_32bit(0));
+
+ new_section(current_asmdata.asmlists[al_procedures],sec_code,'',0);
+ current_asmdata.asmlists[al_procedures].concat(tai_symbol.createname_global('_DLLMainCRTStartup',AT_FUNCTION,0));
+ gen_fpc_dummy(current_asmdata.asmlists[al_procedures]);
+ current_asmdata.asmlists[al_procedures].concat(tai_const.createname('_FPCDummy',0));
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+ { remove all unused units, this happends when units are removed
+ from the uses clause in the source and the ppu was already being loaded }
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ hp2:=hp;
+ hp:=tmodule(hp.next);
+ if hp2.is_unit and
+ not assigned(hp2.globalsymtable) then
+ loaded_units.remove(hp2);
+ end;
+
+ { force exports }
+ uu:=tused_unit(usedunits.first);
+ while assigned(uu) do
+ begin
+ uu.u.globalsymtable.symlist.ForEachCall(@insert_export,uu.u.globalsymtable);
+ { check localsymtable for exports too to get public symbols }
+ uu.u.localsymtable.symlist.ForEachCall(@insert_export,uu.u.localsymtable);
+
+ { create special exports }
+ if (uu.u.flags and uf_init)<>0 then
+ procexport(make_mangledname('INIT$',uu.u.globalsymtable,''));
+ if (uu.u.flags and uf_finalize)<>0 then
+ procexport(make_mangledname('FINALIZE$',uu.u.globalsymtable,''));
+ if (uu.u.flags and uf_threadvars)=uf_threadvars then
+ varexport(make_mangledname('THREADVARLIST',uu.u.globalsymtable,''));
+
+ uu:=tused_unit(uu.next);
+ end;
+
+{$ifdef arm}
+ { Insert .pdata section for arm-wince.
+ It is needed for exception handling. }
+ if target_info.system in [system_arm_wince] then
+ InsertPData;
+{$endif arm}
+
+ { generate debuginfo }
+ if (cs_debuginfo in current_settings.moduleswitches) then
+ current_debuginfo.inserttypeinfo;
+
+ exportlib.generatelib;
+
+ { write all our exports to the import library,
+ needs to be done after exportlib.generatelib; }
+ createimportlibfromexports;
+
+ { generate imports }
+ if current_module.ImportLibraryList.Count>0 then
+ importlib.generatelib;
+
+ { Reference all DEBUGINFO sections from the main .fpc section }
+ if (cs_debuginfo in current_settings.moduleswitches) then
+ current_debuginfo.referencesections(current_asmdata.asmlists[al_procedures]);
+
+ { insert own objectfile }
+ insertobjectfile;
+
+ { assemble and link }
+ create_objectfile;
+
+ { We might need the symbols info if not using
+ the default do_extractsymbolinfo
+ which is a dummy function PM }
+ needsymbolinfo:=do_extractsymbolinfo<>@def_extractsymbolinfo;
+ { release all local symtables that are not needed anymore }
+ if (not needsymbolinfo) then
+ free_localsymtables(current_module.localsymtable);
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+ if (not current_module.is_unit) then
+ begin
+ { finally rewrite all units included into the package }
+ uu:=tused_unit(usedunits.first);
+ while assigned(uu) do
+ begin
+ RewritePPU(uu.u.ppufilename^,uu.u.ppufilename^);
+ uu:=tused_unit(uu.next);
+ end;
+
+ { create the executable when we are at level 1 }
+ if (compile_level=1) then
+ begin
+ { create global resource file by collecting all resource files }
+ CollectResourceFiles;
+ { write .def file }
+ if (cs_link_deffile in current_settings.globalswitches) then
+ deffile.writefile;
+ { insert all .o files from all loaded units and
+ unload the units, we don't need them anymore.
+ Keep the current_module because that is still needed }
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ { the package itself contains no code so far }
+ linker.AddModuleFiles(hp);
+ hp2:=tmodule(hp.next);
+ if (hp<>current_module) and
+ (not needsymbolinfo) then
+ begin
+ loaded_units.remove(hp);
+ hp.free;
+ end;
+ hp:=hp2;
+ end;
+ linker.MakeSharedLibrary
+ end;
+
+ { Give Fatal with error count for linker errors }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ end;
+ end;
+ end;
+
+
+ procedure proc_program(islibrary : boolean);
+ var
+ main_file : tinputfile;
+ hp,hp2 : tmodule;
+ finalize_procinfo,
+ init_procinfo,
+ main_procinfo : tcgprocinfo;
+ force_init_final : boolean;
+ resources_used : boolean;
+ program_name : ansistring;
+ begin
+ DLLsource:=islibrary;
+ Status.IsLibrary:=IsLibrary;
+ Status.IsPackage:=false;
+ Status.IsExe:=true;
+ parse_only:=false;
+ main_procinfo:=nil;
+ init_procinfo:=nil;
+ finalize_procinfo:=nil;
+ resources_used:=false;
+
+ { DLL defaults to create reloc info }
+ if islibrary then
+ begin
+ if not RelocSectionSetExplicitly then
+ RelocSection:=true;
+ end;
+
+ { Relocation works only without stabs under Windows when }
+ { external linker (LD) is used. LD generates relocs for }
+ { stab sections which is not loaded in memory. It causes }
+ { AV error when DLL is loaded and relocation is needed. }
+ { Internal linker does not have this problem. }
+ if RelocSection and
+ (target_info.system in systems_all_windows+[system_i386_wdosx]) and
+ (cs_link_extern in current_settings.globalswitches) then
+ begin
+ include(current_settings.globalswitches,cs_link_strip);
+ { Warning stabs info does not work with reloc section !! }
+ if (cs_debuginfo in current_settings.moduleswitches) and
+ (target_dbg.id=dbg_stabs) then
+ begin
+ Message1(parser_w_parser_reloc_no_debug,current_module.mainsource^);
+ Message(parser_w_parser_win32_debug_needs_WN);
+ exclude(current_settings.moduleswitches,cs_debuginfo);
+ end;
+ end;
+ { get correct output names }
+ main_file := current_scanner.inputfile;
+ while assigned(main_file.next) do
+ main_file := main_file.next;
+
+ current_module.SetFileName(main_file.path^+main_file.name^,true);
+
+ if islibrary then
+ begin
+ consume(_LIBRARY);
+ program_name:=orgpattern;
+ consume(_ID);
+ while token=_POINT do
+ begin
+ consume(_POINT);
+ program_name:=program_name+'.'+orgpattern;
+ consume(_ID);
+ end;
+ current_module.setmodulename(program_name);
+ current_module.islibrary:=true;
+ exportlib.preparelib(program_name);
+
+ if tf_library_needs_pic in target_info.flags then
+ include(current_settings.moduleswitches,cs_create_pic);
+
+ consume(_SEMICOLON);
+ end
+ else
+ { is there an program head ? }
+ if token=_PROGRAM then
+ begin
+ consume(_PROGRAM);
+ program_name:=orgpattern;
+ consume(_ID);
+ while token=_POINT do
+ begin
+ consume(_POINT);
+ program_name:=program_name+'.'+orgpattern;
+ consume(_ID);
+ end;
+ current_module.setmodulename(program_name);
+ if (target_info.system in systems_unit_program_exports) then
+ exportlib.preparelib(program_name);
+ if token=_LKLAMMER then
+ begin
+ consume(_LKLAMMER);
+ repeat
+ consume(_ID);
+ until not try_to_consume(_COMMA);
+ consume(_RKLAMMER);
+ end;
+ consume(_SEMICOLON);
+ end
+ else if (target_info.system in systems_unit_program_exports) then
+ exportlib.preparelib(current_module.realmodulename^);
+
+ { global switches are read, so further changes aren't allowed }
+ current_module.in_global:=false;
+
+ { setup things using the switches }
+ setupglobalswitches;
+
+ { set implementation flag }
+ current_module.in_interface:=false;
+ current_module.interface_compiled:=true;
+
+ { insert after the unit symbol tables the static symbol table }
+ { of the program }
+ current_module.localsymtable:=tstaticsymtable.create(current_module.modulename^,current_module.moduleid);
+
+ { load standard units (system,objpas,profile unit) }
+ loaddefaultunits;
+
+ { Load units provided on the command line }
+ loadautounits;
+
+ {Load the units used by the program we compile.}
+ if token=_USES then
+ loadunits;
+
+ { All units are read, now give them a number }
+ current_module.updatemaps;
+
+ {Insert the name of the main program into the symbol table.}
+ if current_module.realmodulename^<>'' then
+ tabstractunitsymtable(current_module.localsymtable).insertunit(tunitsym.create(current_module.realmodulename^,current_module));
+
+ Message1(parser_u_parsing_implementation,current_module.mainsource^);
+
+ symtablestack.push(current_module.localsymtable);
+
+ { Insert _GLOBAL_OFFSET_TABLE_ symbol if system uses it }
+ maybe_load_got;
+
+ { create whole program optimisation information }
+ current_module.wpoinfo:=tunitwpoinfo.create;
+
+ { The program intialization needs an alias, so it can be called
+ from the bootstrap code.}
+ if islibrary then
+ begin
+ main_procinfo:=create_main_proc(make_mangledname('',current_module.localsymtable,mainaliasname),potype_proginit,current_module.localsymtable);
+ { Win32 startup code needs a single name }
+ if not(target_info.system in systems_darwin) then
+ main_procinfo.procdef.aliasnames.insert('PASCALMAIN')
+ else
+ main_procinfo.procdef.aliasnames.insert(target_info.Cprefix+'PASCALMAIN')
+ end
+ else if (target_info.system in ([system_i386_netware,system_i386_netwlibc,system_powerpc_macos]+systems_darwin)) then
+ begin
+ main_procinfo:=create_main_proc('PASCALMAIN',potype_proginit,current_module.localsymtable);
+ end
+ else
+ begin
+ main_procinfo:=create_main_proc(mainaliasname,potype_proginit,current_module.localsymtable);
+ main_procinfo.procdef.aliasnames.insert('PASCALMAIN');
+ end;
+ main_procinfo.parse_body;
+ { save file pos for debuginfo }
+ current_module.mainfilepos:=main_procinfo.entrypos;
+
+ { Generate specializations of objectdefs methods }
+ generate_specialization_procs;
+
+ { should we force unit initialization? }
+ force_init_final:=tstaticsymtable(current_module.localsymtable).needs_init_final;
+ if force_init_final then
+ init_procinfo:=gen_implicit_initfinal(uf_init,current_module.localsymtable);
+
+ { Add symbol to the exports section for win32 so smartlinking a
+ DLL will include the edata section }
+ if assigned(exportlib) and
+ (target_info.system in [system_i386_win32,system_i386_wdosx]) and
+ ((current_module.flags and uf_has_exports)<>0) then
+ current_asmdata.asmlists[al_procedures].concat(tai_const.createname(make_mangledname('EDATA',current_module.localsymtable,''),0));
+
+ { finalize? }
+ if token=_FINALIZATION then
+ begin
+ { Parse the finalize }
+ finalize_procinfo:=create_main_proc(make_mangledname('',current_module.localsymtable,'finalize'),potype_unitfinalize,current_module.localsymtable);
+ finalize_procinfo.procdef.aliasnames.insert(make_mangledname('FINALIZE$',current_module.localsymtable,''));
+ finalize_procinfo.procdef.aliasnames.insert('PASCALFINALIZE');
+ finalize_procinfo.parse_body;
+ end
+ else
+ if force_init_final then
+ finalize_procinfo:=gen_implicit_initfinal(uf_finalize,current_module.localsymtable);
+
+ { the finalization routine of libraries is generic (and all libraries need to }
+ { be finalized, so they can finalize any units they use }
+ if (islibrary) then
+ exportlib.setfininame(current_asmdata.asmlists[al_procedures],'FPC_LIB_EXIT');
+
+ { all labels must be defined before generating code }
+ if Errorcount=0 then
+ tstoredsymtable(current_module.localsymtable).checklabels;
+
+ { See remark in unit init/final }
+ main_procinfo.generate_code;
+ main_procinfo.resetprocdef;
+ release_main_proc(main_procinfo);
+ if assigned(init_procinfo) then
+ begin
+ { initialization can be implicit only }
+ current_module.flags:=current_module.flags or uf_init;
+ init_procinfo.generate_code;
+ init_procinfo.resetprocdef;
+ release_main_proc(init_procinfo);
+ end;
+ if assigned(finalize_procinfo) then
+ begin
+ if force_init_final or not (has_no_code(finalize_procinfo.code)) then
+ begin
+ finalize_procinfo.generate_code;
+ current_module.flags:=current_module.flags or uf_finalize;
+ end;
+ finalize_procinfo.resetprocdef;
+ release_main_proc(finalize_procinfo);
+ end;
+
+ symtablestack.pop(current_module.localsymtable);
+
+ { consume the last point }
+ consume(_POINT);
+
+ { reset wpo flags for all defs }
+ reset_all_defs;
+
+ if (Errorcount=0) then
+ begin
+ { test static symtable }
+ tstoredsymtable(current_module.localsymtable).allsymbolsused;
+ tstoredsymtable(current_module.localsymtable).allprivatesused;
+ tstoredsymtable(current_module.localsymtable).check_forwards;
+
+ current_module.allunitsused;
+ end;
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+ { remove all unused units, this happens when units are removed
+ from the uses clause in the source and the ppu was already being loaded }
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ hp2:=hp;
+ hp:=tmodule(hp.next);
+ if hp2.is_unit and
+ not assigned(hp2.globalsymtable) then
+ begin
+ loaded_units.remove(hp2);
+ unloaded_units.concat(hp2);
+ end;
+ end;
+
+ { do we need to add the variants unit? }
+ maybeloadvariantsunit;
+
+ { Now that everything has been compiled we know if we need resource
+ support. If not, remove the unit. }
+ resources_used:=MaybeRemoveResUnit;
+
+ linker.initsysinitunitname;
+ if target_info.system in systems_internal_sysinit then
+ begin
+ { add start/halt unit }
+ AddUnit(linker.sysinitunit);
+ end;
+
+{$ifdef arm}
+ { Insert .pdata section for arm-wince.
+ It is needed for exception handling. }
+ if target_info.system in [system_arm_wince] then
+ InsertPData;
+{$endif arm}
+
+ InsertThreadvars;
+
+ { generate rtti/init tables }
+ write_persistent_type_info(current_module.localsymtable);
+
+ { if an Objective-C module, generate rtti and module info }
+ MaybeGenerateObjectiveCImageInfo(nil,current_module.localsymtable);
+
+ { generate wrappers for interfaces }
+ gen_intf_wrappers(current_asmdata.asmlists[al_procedures],current_module.localsymtable,false);
+
+ { generate imports }
+ if current_module.ImportLibraryList.Count>0 then
+ importlib.generatelib;
+
+ { generate debuginfo }
+ if (cs_debuginfo in current_settings.moduleswitches) then
+ current_debuginfo.inserttypeinfo;
+
+ if islibrary or (target_info.system in systems_unit_program_exports) then
+ exportlib.generatelib;
+
+ { Reference all DEBUGINFO sections from the main .fpc section }
+ if (cs_debuginfo in current_settings.moduleswitches) then
+ current_debuginfo.referencesections(current_asmdata.asmlists[al_procedures]);
+
+ { Resource strings }
+ GenerateResourceStrings;
+
+ { Windows widestring needing initialization }
+ InsertWideInits;
+
+ { Resourcestring references (const foo:string=someresourcestring) }
+ InsertResStrInits;
+
+ { insert Tables and StackLength }
+ InsertInitFinalTable;
+ InsertThreadvarTablesTable;
+ InsertResourceTablesTable;
+ InsertWideInitsTablesTable;
+ InsertResStrTablesTable;
+ InsertMemorySizes;
+
+{$ifdef FPC_HAS_SYSTEMS_INTERRUPT_TABLE}
+ if target_info.system in systems_interrupt_table then
+ InsertInterruptTable;
+{$endif FPC_HAS_SYSTEMS_INTERRUPT_TABLE}
+
+ { Insert symbol to resource info }
+ InsertResourceInfo(resources_used);
+
+ { create callframe info }
+ create_dwarf_frame;
+
+ { insert own objectfile }
+ insertobjectfile;
+
+ { assemble and link }
+ create_objectfile;
+
+ { We might need the symbols info if not using
+ the default do_extractsymbolinfo
+ which is a dummy function PM }
+ needsymbolinfo:=
+ (do_extractsymbolinfo<>@def_extractsymbolinfo) or
+ ((current_settings.genwpoptimizerswitches*WPOptimizationsNeedingAllUnitInfo)<>[]);
+
+ { release all local symtables that are not needed anymore }
+ if (not needsymbolinfo) then
+ free_localsymtables(current_module.localsymtable);
+
+ { leave when we got an error }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ exit;
+ end;
+
+ if (not current_module.is_unit) then
+ begin
+ { create the executable when we are at level 1 }
+ if (compile_level=1) then
+ begin
+ { create global resource file by collecting all resource files }
+ CollectResourceFiles;
+ { write .def file }
+ if (cs_link_deffile in current_settings.globalswitches) then
+ deffile.writefile;
+ { insert all .o files from all loaded units and
+ unload the units, we don't need them anymore.
+ Keep the current_module because that is still needed }
+ hp:=tmodule(loaded_units.first);
+ while assigned(hp) do
+ begin
+ linker.AddModuleFiles(hp);
+ hp2:=tmodule(hp.next);
+ if (hp<>current_module) and
+ (not needsymbolinfo) then
+ begin
+ loaded_units.remove(hp);
+ hp.free;
+ end;
+ hp:=hp2;
+ end;
+ { free also unneeded units we didn't free before }
+ if not needsymbolinfo then
+ unloaded_units.Clear;
+ { finally we can create a executable }
+ if DLLSource then
+ linker.MakeSharedLibrary
+ else
+ linker.MakeExecutable;
+
+ { collect all necessary information for whole-program optimization }
+ wpoinfomanager.extractwpoinfofromprogram;
+ end;
+
+
+ { Give Fatal with error count for linker errors }
+ if (Errorcount>0) and not status.skip_error then
+ begin
+ Message1(unit_f_errors_in_unit,tostr(Errorcount));
+ status.skip_error:=true;
+ end;
+ end;
+ end;
+
+end.