Don't add underscore prefix to amd64 symbols
[reactos.git] / reactos / tools / rbuild / module.cpp
index 058c9ee..38a104a 100644 (file)
@@ -12,9 +12,9 @@
  * 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.
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 #include "pch.h"
 #include <assert.h>
@@ -189,11 +189,11 @@ IfableData::IfableData( )
 {
 }
 
-void IfableData::ExtractModules( std::vector<Module*> &modules )
+void IfableData::ExtractModules( std::map<std::string, Module*> &modules )
 {
        size_t i;
        for ( i = 0; i < this->modules.size (); i++ )
-               modules.push_back(this->modules[i]);
+               modules.insert(std::make_pair(this->modules[i]->name, this->modules[i]));
 }
 
 IfableData::~IfableData()
@@ -205,8 +205,8 @@ IfableData::~IfableData()
                delete defines[i];
        for ( i = 0; i < libraries.size (); i++ )
                delete libraries[i];
-       for ( i = 0; i < properties.size (); i++ )
-               delete properties[i];
+       for ( std::map<std::string, Property*>::const_iterator p = properties.begin(); p != properties.end(); ++ p )
+               delete p->second;
        for ( i = 0; i < compilerFlags.size (); i++ )
                delete compilerFlags[i];
        for ( i = 0; i < modules.size(); i++ )
@@ -224,20 +224,43 @@ void IfableData::ProcessXML ()
                defines[i]->ProcessXML ();
        for ( i = 0; i < libraries.size (); i++ )
                libraries[i]->ProcessXML ();
-       for ( i = 0; i < properties.size(); i++ )
-               properties[i]->ProcessXML ();
+       for ( std::map<std::string, Property*>::const_iterator p = properties.begin(); p != properties.end(); ++ p )
+               p->second->ProcessXML ();
        for ( i = 0; i < compilerFlags.size(); i++ )
                compilerFlags[i]->ProcessXML ();
        for ( i = 0; i < compilationUnits.size (); i++ )
                compilationUnits[i]->ProcessXML ();
 }
 
+bool Module::GetBooleanAttribute ( const XMLElement& moduleNode, const char * name, bool default_value )
+{
+       const XMLAttribute* att = moduleNode.GetAttribute ( name, false );
+       if ( att != NULL )
+       {
+               const char* p = att->value.c_str();
+               if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
+                       return true;
+               else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
+                       return false;
+               else
+               {
+                       throw InvalidAttributeValueException (
+                               moduleNode.location,
+                               name,
+                               att->value );
+               }
+       }
+       else
+               return default_value;
+}
+
 Module::Module ( const Project& project,
                  const XMLElement& moduleNode,
                  const string& modulePath )
        : project (project),
          node (moduleNode),
          importLibrary (NULL),
+         delayImportLibrary (NULL),
          metadata (NULL),
          bootSector (NULL),
          bootstrap (NULL),
@@ -282,24 +305,7 @@ Module::Module ( const Project& project,
        else
                extension = GetDefaultModuleExtension ();
 
-       att = moduleNode.GetAttribute ( "unicode", false );
-       if ( att != NULL )
-       {
-               const char* p = att->value.c_str();
-               if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
-                       isUnicode = true;
-               else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
-                       isUnicode = false;
-               else
-               {
-                       throw InvalidAttributeValueException (
-                               moduleNode.location,
-                               "unicode",
-                               att->value );
-               }
-       }
-       else
-               isUnicode = false;
+       isUnicode = GetBooleanAttribute ( moduleNode, "unicode" );
 
        if (isUnicode)
        {
@@ -337,49 +343,50 @@ Module::Module ( const Project& project,
        else
                baseaddress = GetDefaultModuleBaseaddress ();
 
-       att = moduleNode.GetAttribute ( "mangledsymbols", false );
-       if ( att != NULL )
+       isStartupLib = GetBooleanAttribute ( moduleNode, "isstartuplib" );
+       isCRT = GetBooleanAttribute ( moduleNode, "iscrt", GetDefaultModuleIsCRT () );
+
+       att = moduleNode.GetAttribute ( "crt", false );
+       if ( att != NULL)
        {
-               const char* p = att->value.c_str();
-               if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
-                       mangledSymbols = true;
-               else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
-                       mangledSymbols = false;
-               else
-               {
-                       throw InvalidAttributeValueException (
-                               moduleNode.location,
-                               "mangledsymbols",
-                               att->value );
-               }
+               CRT = att->value;
+
+               if ( stricmp ( CRT.c_str (), "auto" ) == 0 )
+                       CRT = GetDefaultModuleCRT ();
        }
        else
-               mangledSymbols = false;
-
-       att = moduleNode.GetAttribute ( "underscoresymbols", false );
-       if ( att != NULL )
-               underscoreSymbols = att->value == "true";
+               CRT = GetDefaultModuleCRT ();
+
+       const char * crtAttr = CRT.c_str ();
+       if ( crtAttr == NULL || stricmp ( crtAttr, "none" ) == 0 )
+               dynamicCRT = false;
+       else if ( stricmp ( crtAttr, "libc" ) == 0 )
+               dynamicCRT = false;
+       else if ( stricmp ( crtAttr, "msvcrt" ) == 0 )
+               dynamicCRT = true;
+       else if ( stricmp ( crtAttr, "libcntpr" ) == 0 )
+               dynamicCRT = false;
+       else if ( stricmp ( crtAttr, "ntdll" ) == 0 )
+               dynamicCRT = true;
+       else if ( stricmp ( crtAttr, "static" ) == 0 )
+               dynamicCRT = false;
+       else if ( stricmp ( crtAttr, "dll" ) == 0 )
+               dynamicCRT = true;
        else
-               underscoreSymbols = false;
+       {
+               throw InvalidAttributeValueException (
+                       moduleNode.location,
+                       "crt",
+                       std::string ( crtAttr ) );
+       }
 
-       att = moduleNode.GetAttribute ( "isstartuplib", false );
-       if ( att != NULL )
+       if ( isCRT && dynamicCRT )
        {
-               const char* p = att->value.c_str();
-               if ( !stricmp ( p, "true" ) || !stricmp ( p, "yes" ) )
-                       isStartupLib = true;
-               else if ( !stricmp ( p, "false" ) || !stricmp ( p, "no" ) )
-                       isStartupLib = false;
-               else
-               {
-                       throw InvalidAttributeValueException (
-                               moduleNode.location,
-                               "isstartuplib",
-                               att->value );
-               }
+               throw XMLInvalidBuildFileException (
+                       moduleNode.location,
+                       "C runtime module '%s' cannot be compiled for a dynamically-linked C runtime",
+                       name.c_str() );
        }
-       else
-               isStartupLib = false;
 
        att = moduleNode.GetAttribute ( "prefix", false );
        if ( att != NULL )
@@ -438,6 +445,8 @@ Module::Module ( const Project& project,
        }
        if ( att != NULL )
                allowWarnings = att->value == "true";
+       else if ( project.allowWarningsSet )
+               allowWarnings = project.allowWarnings;
        else
                allowWarnings = false;
 
@@ -508,6 +517,8 @@ Module::~Module ()
                delete linkerFlags[i];
        for ( i = 0; i < stubbedComponents.size(); i++ )
                delete stubbedComponents[i];
+       for ( i = 0; i < cdfiles.size (); i++ )
+               delete cdfiles[i];
        if ( linkerScript )
                delete linkerScript;
        if ( pch )
@@ -527,7 +538,7 @@ Module::~Module ()
        if ( autoRegister )
                delete autoRegister;
        if ( output )
-               delete output;          
+               delete output;
 }
 
 void
@@ -585,6 +596,48 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                                   const string& relative_path,
                                ParseContext& parseContext )
 {
+       const XMLAttribute* att;
+
+       att = e.GetAttribute ( "compilerset", false );
+
+       if ( att )
+       {
+               CompilerSet compilerSet;
+
+               if ( att->value == "msc" )
+                       compilerSet = MicrosoftC;
+               else if ( att->value == "gcc" )
+                       compilerSet = GnuGcc;
+               else
+                       throw InvalidAttributeValueException (
+                               e.location,
+                               "compilerset",
+                               att->value );
+
+               if ( compilerSet != project.configuration.Compiler )
+                       return;
+       }
+
+       att = e.GetAttribute ( "linkerset", false );
+
+       if ( att )
+       {
+               LinkerSet linkerSet;
+
+               if ( att->value == "mslink" )
+                       linkerSet = MicrosoftLink;
+               else if ( att->value == "ld" )
+                       linkerSet = GnuLd;
+               else
+                       throw InvalidAttributeValueException (
+                               e.location,
+                               "linkerset",
+                               att->value );
+
+               if ( linkerSet != project.configuration.Linker )
+                       return;
+       }
+
        CompilationUnit* pOldCompilationUnit = parseContext.compilationUnit;
        bool subs_invalid = false;
        string subpath ( relative_path );
@@ -657,7 +710,10 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
        }
        else if ( e.name == "library" && e.value.size () )
        {
+               const XMLAttribute* att = e.GetAttribute ( "delayimport", false );
                Library* pLibrary = new Library ( e, *this, e.value );
+               if ( att && !stricmp ( att->value.c_str(), "true" ) )
+                       pLibrary->delayimp = true;
                non_if_data.libraries.push_back ( pLibrary );
                subs_invalid = true;
        }
@@ -688,7 +744,7 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                non_if_data.includes.push_back ( include );
                subs_invalid = true;
        }
-       else if ( e.name == "define" )
+       else if ( e.name == "define" || e.name == "redefine" )
        {
                Define* pDefine = new Define ( project, this, e );
                non_if_data.defines.push_back ( pDefine );
@@ -722,7 +778,8 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                                e.location,
                                "Only one <importlibrary> is valid per module" );
                }
-               SetImportLibrary ( new ImportLibrary ( project, e, this ) );
+               SetImportLibrary ( new ImportLibrary ( project, e, this, false ) );
+               SetDelayImportLibrary ( new ImportLibrary ( project, e, this, true ) );
                subs_invalid = true;
        }
        else if ( e.name == "if" || e.name == "ifnot" )
@@ -731,13 +788,17 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                name = e.GetAttribute ( "property", true );
                assert( name );
                const Property *property = project.LookupProperty( name->value );
-               if ( !property )
+               const string *PropertyValue;
+               const string EmptyString;
+
+               if (property)
                {
-                       // Property not found
-                       throw InvalidOperationException ( __FILE__,
-                                                         __LINE__,
-                                                         "Test on unknown property '%s' at %s",
-                                                         name->value.c_str (), e.location.c_str () );
+                       PropertyValue = &property->value;
+               }
+               else
+               {
+                       // Property does not exist, treat it as being empty
+                       PropertyValue = &EmptyString;
                }
 
                const XMLAttribute* value;
@@ -745,7 +806,7 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                assert( value );
 
                bool negate = ( e.name == "ifnot" );
-               bool equality = ( property->value == value->value );
+               bool equality = ( *PropertyValue == value->value );
                if ( equality == negate )
                {
                        // Failed, skip this element
@@ -850,6 +911,12 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                autoRegister = new AutoRegister ( project, this, e );
                subs_invalid = true;
        }
+       else if ( e.name == "cdfile" )
+       {
+               CDFile* cdfile = new CDFile ( project, e, subpath );
+               cdfiles.push_back ( cdfile );
+               subs_invalid = true;
+       }
        if ( subs_invalid && e.subElements.size() > 0 )
        {
                throw XMLInvalidBuildFileException (
@@ -857,6 +924,8 @@ Module::ProcessXMLSubElement ( const XMLElement& e,
                        "<%s> cannot have sub-elements",
                        e.name.c_str() );
        }
+       for ( size_t i = 0; i < cdfiles.size (); i++ )
+               cdfiles[i]->ProcessXML ();
        for ( size_t i = 0; i < e.subElements.size (); i++ )
                ProcessXMLSubElement ( *e.subElements[i], subdirectory, subpath, parseContext );
        parseContext.compilationUnit = pOldCompilationUnit;
@@ -905,10 +974,6 @@ Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
                return Iso;
        if ( attribute.value == "liveiso" )
                return LiveIso;
-       if ( attribute.value == "isoregtest" )
-               return IsoRegTest;
-       if ( attribute.value == "liveisoregtest" )
-               return LiveIsoRegTest;
        if ( attribute.value == "test" )
                return Test;
        if ( attribute.value == "rpcserver" )
@@ -921,6 +986,8 @@ Module::GetModuleType ( const string& location, const XMLAttribute& attribute )
                return Alias;
        if ( attribute.value == "idlheader" )
                return IdlHeader;
+       if ( attribute.value == "idlinterface" )
+               return IdlInterface;
        if ( attribute.value == "embeddedtypelib" )
                return EmbeddedTypeLib;
        if ( attribute.value == "elfexecutable" )
@@ -957,8 +1024,6 @@ Module::GetTargetDirectoryTree () const
                case BootProgram:
                case Iso:
                case LiveIso:
-               case IsoRegTest:
-               case LiveIsoRegTest:
                case ElfExecutable:
                case Cabinet:
                        return OutputDirectory;
@@ -971,6 +1036,7 @@ Module::GetTargetDirectoryTree () const
                case RpcProxy:
                case Alias:
                case IdlHeader:
+               case IdlInterface:
                case MessageHeader:
                        return IntermediateDirectory;
                case TypeDontCare:
@@ -1019,14 +1085,13 @@ Module::GetDefaultModuleExtension () const
                        return ".o";
                case Iso:
                case LiveIso:
-               case IsoRegTest:
-               case LiveIsoRegTest:
                        return ".iso";
                case Test:
                        return ".exe";
                case RpcServer:
                case RpcClient:
                case RpcProxy:
+               case IdlInterface:
                        return ".o";
                case Alias:
                case ElfExecutable:
@@ -1048,7 +1113,8 @@ Module::GetDefaultModuleEntrypoint () const
        switch ( type )
        {
                case Kernel:
-                       return "KiSystemStartup";
+                       if (Environment::GetArch() == "arm") return "KiSystemStartup";
+            return "KiSystemStartup@4";
                case KeyboardLayout:
                case KernelModeDLL:
                case KernelModeDriver:
@@ -1059,23 +1125,17 @@ Module::GetDefaultModuleEntrypoint () const
             return "DllMainCRTStartup@12";
                case NativeCUI:
             if (Environment::GetArch() == "arm") return "NtProcessStartup";
-            return "NtProcessStartup@4";            
+            return "NtProcessStartup@4";
                case Win32DLL:
                case Win32OCX:
             if (Environment::GetArch() == "arm") return "DllMain";
                        return "DllMain@12";
                case Win32CUI:
                case Test:
-                       if ( isUnicode )
-                               return "wmainCRTStartup";
-                       else
-                               return "mainCRTStartup";
+                       return "mainCRTStartup";
                case Win32SCR:
                case Win32GUI:
-                       if ( isUnicode )
-                               return "wWinMainCRTStartup";
-                       else
-                               return "WinMainCRTStartup";
+                       return "WinMainCRTStartup";
                case BuildTool:
                case StaticLibrary:
                case HostStaticLibrary:
@@ -1084,14 +1144,13 @@ Module::GetDefaultModuleEntrypoint () const
                case BootSector:
                case Iso:
                case LiveIso:
-               case IsoRegTest:
-               case LiveIsoRegTest:
                case RpcServer:
                case RpcClient:
                case RpcProxy:
                case Alias:
                case BootProgram:
                case IdlHeader:
+               case IdlInterface:
                case MessageHeader:
                case ElfExecutable:
                case EmbeddedTypeLib:
@@ -1136,14 +1195,13 @@ Module::GetDefaultModuleBaseaddress () const
                case BootSector:
                case Iso:
                case LiveIso:
-               case IsoRegTest:
-               case LiveIsoRegTest:
                case RpcServer:
                case RpcClient:
                case RpcProxy:
                case Alias:
                case BootProgram:
                case IdlHeader:
+               case IdlInterface:
                case MessageHeader:
                case EmbeddedTypeLib:
                case Cabinet:
@@ -1155,6 +1213,66 @@ Module::GetDefaultModuleBaseaddress () const
                                          __LINE__ );
 }
 
+std::string
+Module::GetDefaultModuleCRT () const
+{
+       if ( isCRT )
+               return "static";
+
+       switch ( type )
+       {
+               case Kernel:
+                       return "static";
+               case Win32DLL:
+               case Win32OCX:
+                       return "ntdll";
+               case NativeDLL:
+               case NativeCUI:
+                       return "ntdll";
+               case Win32CUI:
+               case Win32SCR:
+               case Win32GUI:
+                       return "msvcrt";
+               case Test:
+                       return "msvcrt"; // BUGBUG: not sure about this
+               case KeyboardLayout:
+                       return "none";
+               case KernelModeDLL:
+               case KernelModeDriver:
+                       return "dll";
+               case BootLoader:
+                       return "libcntpr";
+               case ElfExecutable:
+               case BuildTool:
+               case StaticLibrary:
+               case HostStaticLibrary:
+               case ObjectLibrary:
+               case BootSector:
+               case Iso:
+               case LiveIso:
+               case RpcServer:
+               case RpcClient:
+               case RpcProxy:
+               case Alias:
+               case BootProgram:
+               case IdlHeader:
+               case IdlInterface:
+               case MessageHeader:
+               case EmbeddedTypeLib:
+               case Cabinet:
+               case TypeDontCare:
+                       return "none";
+       }
+       throw InvalidOperationException ( __FILE__,
+                                         __LINE__ );
+}
+
+bool
+Module::GetDefaultModuleIsCRT () const
+{
+       return type == Kernel;
+}
+
 bool
 Module::HasImportLibrary () const
 {
@@ -1188,13 +1306,12 @@ Module::IsDLL () const
                case BootProgram:
                case Iso:
                case LiveIso:
-               case IsoRegTest:
-               case LiveIsoRegTest:
                case RpcServer:
                case RpcClient:
                case RpcProxy:
                case Alias:
                case IdlHeader:
+               case IdlInterface:
                case MessageHeader:
                case EmbeddedTypeLib:
                case ElfExecutable:
@@ -1235,15 +1352,24 @@ Module::GetInvocationTarget ( const int index ) const
 }
 
 string
-Module::GetEntryPoint(bool leadingUnderscore) const
+Module::GetEntryPoint() const
 {
        string result = "";
        if (entrypoint == "0" || entrypoint == "0x0")
                return "0";
-       if (leadingUnderscore)
+       
+       if (Environment::GetArch() != "arm" && Environment::GetArch() != "amd64")
                result = "_";
 
        result += entrypoint;
+
+       if (Environment::GetArch() == "amd64")
+       {
+               size_t at_index = result.find_last_of( '@' );
+               if ( at_index != result.npos )
+                       return result.substr (0, at_index );
+       }
+
        return result;
 }
 
@@ -1287,6 +1413,40 @@ Module::SetImportLibrary ( ImportLibrary* importLibrary )
                                        HasImportLibrary () ? "lib" + name + ".a" : output->name );
 }
 
+void
+Module::SetDelayImportLibrary ( ImportLibrary* importLibrary )
+{
+       this->delayImportLibrary = importLibrary;
+}
+
+std::string
+Module::GetDllName () const
+{
+       if ( importLibrary && !importLibrary->dllname.empty() )
+               return importLibrary->dllname;
+       else if ( output )
+               return output->name;
+       else
+               throw new InvalidOperationException ( __FILE__, __LINE__, "Module %s has no dllname." );
+}
+
+SpecFileType
+Module::IsSpecDefinitionFile () const
+{
+       if(!importLibrary)
+               return None;
+
+       std::string ext = GetExtension ( *importLibrary->source );
+
+       if ( ext == ".spec" )
+               return Spec;
+
+       if ( ext == ".pspec" )
+               return PSpec;
+
+       return None;
+}
+
 
 File::File ( DirectoryLocation directory,
              const string& relative_path,
@@ -1339,7 +1499,8 @@ Library::Library ( const XMLElement& _node,
        : node(&_node),
          module(_module),
          name(_name),
-         importedModule(_module.project.LocateModule(_name))
+         importedModule(_module.project.LocateModule(_name)),
+         delayimp(false)
 {
        if ( module.name == name )
        {
@@ -1363,8 +1524,17 @@ Library::Library ( const Module& _module,
        : node(NULL),
          module(_module),
          name(_name),
-         importedModule(_module.project.LocateModule(_name))
+         importedModule(_module.project.LocateModule(_name)),
+         delayimp(false)
 {
+       if ( !importedModule )
+       {
+               throw XMLInvalidBuildFileException (
+                       "<internal>",
+                       "module '%s' trying to import non-existant module '%s'",
+                       module.name.c_str(),
+                       name.c_str() );
+       }
 }
 
 void
@@ -1598,9 +1768,7 @@ bool
 Bootsector::IsSupportedModuleType ( ModuleType type )
 {
        if ( type == Iso ||
-            type == LiveIso ||
-            type == IsoRegTest ||
-                type == LiveIsoRegTest )
+            type == LiveIso )
        {
                return true;
        }
@@ -1666,12 +1834,14 @@ Metadata::Metadata ( const XMLElement& _node,
 ImportLibrary::~ImportLibrary ()
 {
        delete source;
+       delete target;
 }
 
 
 ImportLibrary::ImportLibrary ( const Project& project,
                                const XMLElement& node,
-                               const Module* module )
+                               const Module* module,
+                               bool delayimp )
        : XmlNode ( project, node ),
          module (module)
 {
@@ -1713,19 +1883,9 @@ ImportLibrary::ImportLibrary ( const Project& project,
                                                               "root",
                                                               att->value );
        }
-       else
-       {
-               size_t index = definition->value.rfind ( ".spec.def" );
-               if ( index != string::npos )
-                       directory = IntermediateDirectory;
-       }
 
        if ( dllname )
                this->dllname = dllname->value;
-       else if ( module->type == StaticLibrary || module->type == HostStaticLibrary )
-               throw XMLInvalidBuildFileException (
-                   node.location,
-                   "<importlibrary> dllname attribute required." );
 
        size_t index = definition->value.find_last_of ( "/\\" );
        if ( index == string::npos )
@@ -1744,6 +1904,11 @@ ImportLibrary::ImportLibrary ( const Project& project,
                                            name,
                                            &node );
        }
+
+       target = new FileLocation ( IntermediateDirectory,
+                                   base->output->relative_path,
+                                   "lib" + module->name + (delayimp ? ".delayimp.a" :  ".a" ));
+
 }