Back to index

lightning-sunbird  0.9+nobinonly
mac_xpt_linker.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1998
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038        mac_xpt_linker.cpp
00039        
00040        CodeWarrior plugin linker, links together multiple .xpt files.
00041        
00042        by Patrick C. Beard.
00043  */
00044 
00045 /* standard headers */
00046 #include <stdio.h>
00047 #include <string.h>
00048 #include <setjmp.h>
00049 
00050 /* system headers */
00051 #include <Files.h>
00052 #include <Strings.h>
00053 #include <Aliases.h>
00054 #include <Resources.h>
00055 
00056 /* compiler headers */
00057 #include "DropInCompilerLinker.h"
00058 #include "CompilerMapping.h"
00059 #include "CWPluginErrors.h"
00060 
00061 /* project headers */
00062 #include "mac_xpidl_panel.h"
00063 #include "mac_console.h"
00064 #include "mac_strings.h"
00065 #include "FullPath.h"
00066 #include "MoreFilesExtras.h"
00067 
00068 /* use standard CodeWarrior debugger */
00069 #define kDebuggerCreator    'MWDB'
00070 
00071 /* prototypes of local functions */
00072 static CWResult      Link(CWPluginContext context);
00073 static CWResult      Disassemble(CWPluginContext context);
00074 static CWResult      GetTargetInfo(CWPluginContext context);
00075 
00076 extern "C" {
00077 pascal short xpt_linker(CWPluginContext context);
00078 int xptlink_main(int argc, char* argv[]);
00079 int xptdump_main(int argc, char* argv[]);
00080 
00081 FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode);
00082 size_t mac_get_file_length(const char* filename);
00083 }
00084 
00085 /* external variables */
00086 extern jmp_buf exit_jump;
00087 extern int exit_status;
00088 
00089 /* global variables */
00090 CWPluginContext gPluginContext;
00091 
00092 /* local variables */
00093 static CWFileSpec gOutputDirectory;
00094 static CWFileSpec gObjectCodeDirectory;
00095 
00096 /*
00097  *     xpt_linker    -      main entry-point for linker plugin
00098  *
00099  */
00100 pascal short xpt_linker(CWPluginContext context)
00101 {
00102        long request;
00103        if (CWGetPluginRequest(context, &request) != cwNoErr)
00104               return cwErrRequestFailed;
00105        
00106        gPluginContext = context;
00107        short result = cwNoErr;
00108               
00109        /* dispatch on linker request */
00110        switch (request) {
00111        case reqInitLinker:
00112               /* linker has just been loaded into memory */
00113               break;
00114               
00115        case reqTermLinker:
00116               /* linker is about to be unloaded from memory */
00117               break;
00118               
00119        case reqLink:
00120               /* build the final executable */
00121               result = Link(context);
00122               break;
00123               
00124        case reqDisassemble:
00125               /* disassemble object code for a given project file */
00126               result = Disassemble(context);
00127               break;
00128        
00129        case reqTargetInfo:
00130               /* return info describing target characteristics */
00131               result = GetTargetInfo(context);
00132               break;
00133               
00134        default:
00135               result = cwErrRequestFailed;
00136               break;
00137        }
00138        
00139        result = CWDonePluginRequest(context, result);
00140        
00141        /* return result code */
00142        return result;
00143 }
00144 
00145 static char* full_path_to(const FSSpec& file)
00146 {
00147        short len = 0;
00148        Handle fullPath = NULL;
00149        if (FSpGetFullPath(&file, &len, &fullPath) == noErr && fullPath != NULL) {
00150               char* path = new char[1 + len];
00151               if (path != NULL) {
00152                      BlockMoveData(*fullPath, path, len);
00153                      path[len] = '\0';
00154               }
00155               DisposeHandle(fullPath);
00156               return path;
00157        }
00158        return NULL;
00159 }
00160 
00164 static char* full_path_to(short vRefNum, long dirID)
00165 {
00166        long parID;
00167        if (GetParentID(vRefNum, dirID, NULL, &parID) == noErr) {
00168               FSSpec dirSpec = { vRefNum, parID };
00169               if (GetDirName(vRefNum, dirID, dirSpec.name) == noErr) {
00170                      return full_path_to(dirSpec);
00171               }
00172        }
00173        return NULL;
00174 }
00175 
00180 size_t mac_get_file_length(const char* filename)
00181 {
00182        FSSpec fileSpec = { gObjectCodeDirectory.vRefNum, gObjectCodeDirectory.parID };
00183        c2p_strcpy(fileSpec.name, filename);
00184        long dataSize, rsrcSize;
00185        if (FSpGetFileSize(&fileSpec, &dataSize, &rsrcSize) != noErr)
00186               dataSize = 0;
00187        return dataSize;
00188 }
00189 
00194 FILE* std::fopen(const char* filename, const char *mode)
00195 {
00196        CWFileSpec& fileDir = (mode[0] == 'r' ? gObjectCodeDirectory : gOutputDirectory);
00197        FSSpec fileSpec = { fileDir.vRefNum, fileDir.parID };
00198        c2p_strcpy(fileSpec.name, filename);
00199        return FSp_fopen(&fileSpec, mode);
00200 }
00201 
00202 static CWResult GetSettings(CWPluginContext context, XPIDLSettings& settings)
00203 {
00204        CWMemHandle   settingsHand;
00205        CWResult err = CWGetNamedPreferences(context, kXPIDLPanelName, &settingsHand);
00206        if (!CWSUCCESS(err))
00207               return err;
00208        
00209        XPIDLSettings* settingsPtr = NULL;
00210        err = CWLockMemHandle(context, settingsHand, false, (void**)&settingsPtr);
00211        if (!CWSUCCESS(err))
00212               return err;
00213        
00214        settings = *settingsPtr;
00215        
00216        err = CWUnlockMemHandle(context, settingsHand);
00217        if (!CWSUCCESS(err))
00218               return err;
00219 
00220        return cwNoErr;
00221 }
00222 
00223 static CWResult LinkHeaders(CWPluginContext context, XPIDLSettings& settings)
00224 {
00225        // find out how many files there are to link.
00226        long fileCount = 0;
00227        CWResult err = CWGetProjectFileCount(context, &fileCount);
00228        if (err != cwNoErr || fileCount == 0)
00229               return err;
00230 
00231        // get the output directory.
00232        FSSpec outputDir;
00233        err = CWGetOutputFileDirectory(context, &outputDir);
00234        if (!CWSUCCESS(err))
00235               return err;
00236        
00237        // enumerate all of the output header files, and make aliases to them in
00238        // the output directory.
00239        for (long index = 0; (err == cwNoErr) && (index < fileCount); index++) {
00240               // get the name of each output file.
00241               CWFileSpec outputFile;
00242               err = CWGetStoredObjectFileSpec(context, index, &outputFile);
00243               if (err == cwNoErr) {
00244                      FInfo info;
00245                      err = FSpGetFInfo(&outputFile, &info);
00246                      
00247                      FSSpec aliasFile = { outputDir.vRefNum, outputDir.parID };
00248                      BlockMoveData(outputFile.name, aliasFile.name, 1 + outputFile.name[0]);
00249                      
00250                      AliasHandle alias = NULL;
00251                      if (NewAliasMinimal(&outputFile, &alias) == noErr) {
00252                             // recreate the alias file from scratch.
00253                             FSpDelete(&aliasFile);
00254                             FSpCreateResFile(&aliasFile, info.fdCreator, info.fdType, smRoman);
00255                             short refNum = FSpOpenResFile(&aliasFile, fsRdWrPerm);
00256                             if (refNum != -1) {
00257                                    UseResFile(refNum);
00258                                    AddResource(Handle(alias), rAliasType, 0, aliasFile.name);
00259                                    ReleaseResource(Handle(alias));
00260                                    UpdateResFile(refNum);
00261                                    CloseResFile(refNum);
00262                             }
00263                             // finally, mark the newly created file as an alias file.
00264                             FSpGetFInfo(&aliasFile, &info);
00265                             info.fdFlags |= kIsAlias;
00266                             FSpSetFInfo(&aliasFile, &info);
00267                      }
00268               }
00269        }
00270        
00271        // create the target file in the output directory.
00272        BlockMoveData(settings.output, outputDir.name, 1 + settings.output[0]);
00273        FILE* outputFile = FSp_fopen(&outputDir, "w");
00274        if (outputFile != NULL) fclose(outputFile);
00275 
00276        return err;
00277 }
00278 
00279 static CWResult LinkTypeLib(CWPluginContext context, XPIDLSettings& settings)
00280 {
00281        // find out how many files there are to link.
00282        long fileCount = 0;
00283        CWResult err = CWGetProjectFileCount(context, &fileCount);
00284        if (err != cwNoErr || fileCount == 0)
00285               return err;
00286 
00287        // assemble the argument list.
00288        // { "xpt_link", outputFile, inputFile1, ..., inputFileN, NULL }
00289        char** argv = new char*[2 + fileCount + 1];
00290        int argc = 0;
00291        argv[argc++] = "xpt_link";
00292 
00293        // get the output directory.
00294        err = CWGetOutputFileDirectory(context, &gOutputDirectory);
00295        if (!CWSUCCESS(err))
00296               return err;
00297        
00298        // get the object code directory.
00299        err = CWGetStoredObjectFileSpec(context, 0, &gObjectCodeDirectory);
00300        if (!CWSUCCESS(err))
00301               return err;
00302 
00303        // push the output file name.
00304        if ((argv[argc++] = p2c_strdup(settings.output)) == NULL)
00305               return cwErrOutOfMemory;
00306 
00307        for (long index = 0; (err == cwNoErr) && (index < fileCount); index++) {
00308               // get the name of each output file.
00309               CWFileSpec outputFile;
00310               err = CWGetStoredObjectFileSpec(context, index, &outputFile);
00311               if (err == cwNoErr) {
00312                      if ((argv[argc++] = p2c_strdup(outputFile.name)) == NULL) {
00313                             err = cwErrOutOfMemory;
00314                             break;
00315                      }
00316               }
00317        }
00318        
00319        if (err != cwNoErr)
00320               return err;
00321        
00322        // trap calls to exit, which longjmp back to here.
00323        if (setjmp(exit_jump) == 0) {
00324               if (xptlink_main(argc, argv) != 0)
00325                      err = cwErrRequestFailed;
00326        } else {
00327               // evidently the good old exit function got called.
00328               if (exit_status != 0)
00329                      err = cwErrRequestFailed;
00330        }
00331        
00332        return err;
00333 }
00334 
00335 static CWResult      Link(CWPluginContext context)
00336 {
00337        // load the relevant prefs.
00338        XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false };
00339        CWResult err = GetSettings(context, settings);
00340        if (err != cwNoErr)
00341               return err;
00342 
00343        switch (settings.mode) {
00344        case kXPIDLModeHeader:
00345               return LinkHeaders(context, settings);
00346        case kXPIDLModeTypelib:
00347               return LinkTypeLib(context, settings);
00348        default:
00349               return cwNoErr;
00350        }
00351 }
00352 
00353 static CWResult      Disassemble(CWPluginContext context)
00354 {
00355        CWResult err = noErr;
00356 
00357        // cache the project's output directory.
00358        err = CWGetOutputFileDirectory(gPluginContext, &gOutputDirectory);
00359        if (!CWSUCCESS(err))
00360               return err;
00361 
00362        long fileNum;
00363        err = CWGetMainFileNumber(context, &fileNum);
00364        if (!CWSUCCESS(err))
00365               return err;
00366 
00367        // get the output file's location from the stored object data.
00368        err = CWGetStoredObjectFileSpec(context, fileNum, &gObjectCodeDirectory);
00369        if (!CWSUCCESS(err))
00370               return err;
00371        
00372        char* outputName = p2c_strdup(gObjectCodeDirectory.name);
00373        if (outputName == NULL)
00374               return cwErrOutOfMemory;
00375 
00376        XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false };
00377        GetSettings(context, settings);
00378 
00379        // build an argument list and call xpt_dump.
00380        int argc = 1;
00381        char* argv[] = { "xpt_dump", NULL, NULL, NULL };
00382        if (settings.verbose) argv[argc++] = "-v";
00383        argv[argc++] = outputName;
00384        
00385        // trap calls to exit, which longjmp back to here.
00386        if (setjmp(exit_jump) == 0) {
00387               if (xptdump_main(argc, argv) != 0)
00388                      err = cwErrRequestFailed;
00389        } else {
00390               // evidently the good old exit function got called.
00391               if (exit_status != 0)
00392                      err = cwErrRequestFailed;
00393        }
00394 
00395        delete[] outputName;
00396 
00397        if (err == noErr) {
00398               // display the disassembly in its own fresh text window.
00399               CWNewTextDocumentInfo info = {
00400                      NULL,
00401                      mac_console_handle,
00402                      false
00403               };
00404               CWResizeMemHandle(context, mac_console_handle, mac_console_count);
00405               err = CWCreateNewTextDocument(context, &info);
00406        }
00407 
00408        return err;
00409 }
00410 
00411 static CWResult      GetTargetInfo(CWPluginContext context)
00412 {
00413        CWTargetInfo targ;
00414        memset(&targ, 0, sizeof(targ));
00415        
00416        CWResult err = CWGetOutputFileDirectory(context, &targ.outfile);
00417        targ.outputType = linkOutputFile;
00418        targ.symfile = targ.outfile;       /* location of SYM file */
00419        targ.linkType = exelinkageFlat;
00420        targ.targetCPU = '****';
00421        targ.targetOS = '****';
00422        
00423        // load the relevant settings.
00424        XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false };
00425        err = GetSettings(context, settings);
00426        if (err != cwNoErr)
00427               return err;
00428        
00429 #if CWPLUGIN_HOST == CWPLUGIN_HOST_MACOS
00430        // tell the IDE about the output file.
00431        targ.outfileCreator         = 'MMCH';
00432        targ.outfileType            = 'CWIE';
00433        targ.debuggerCreator = kDebuggerCreator;  /* so IDE can locate our debugger  */
00434 
00435        BlockMoveData(settings.output, targ.outfile.name, 1 + settings.output[0]);
00436        targ.symfile.name[0] = 0;
00437 #endif
00438 
00439 #if CWPLUGIN_HOST == CWPLUGIN_HOST_WIN32
00440        targ.debugHelperIsRegKey = true;
00441        *(long*)targ.debugHelperName = kDebuggerCreator;
00442        targ.debugHelperName[4] = 0;
00443        strcat(targ.outfile.path, "\\");
00444        strcat(targ.outfile.path, prefsData.outfile);
00445        strcpy(targ.symfile.path, targ.outfile.path);
00446        strcat(targ.symfile.path, ".SYM");
00447 #endif
00448 
00449        targ.runfile                = targ.outfile;
00450        targ.linkAgainstFile = targ.outfile;
00451 
00452        /* we can only run applications */
00453        // targ.canRun = (prefsData.projtype == kProjTypeApplication);
00454        
00455        /* we can only debug if we have a SYM file */
00456        // targ.canDebug = prefsData.linksym;     
00457        
00458        err = CWSetTargetInfo(context, &targ);
00459        
00460        return err;
00461 }
00462 
00463 #if 0
00464 
00465 #if CW_USE_PRAGMA_EXPORT
00466 #pragma export on
00467 #endif
00468 
00469 CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize)
00470 {
00471        static const DropInFlags sFlags = {
00472               kCurrentDropInFlagsVersion,
00473               CWDROPINLINKERTYPE,
00474               DROPINCOMPILERLINKERAPIVERSION_7,
00475               (linkMultiTargAware | linkAlwaysReload),
00476               0,
00477               DROPINCOMPILERLINKERAPIVERSION
00478        };
00479        
00480        *flags = &sFlags;
00481        *flagsSize = sizeof(sFlags);
00482        
00483        return cwNoErr;
00484 }
00485 
00486 CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName)
00487 {
00488        static const char* sDropInName = "xpt Linker";
00489        *dropinName = sDropInName;
00490        return cwNoErr;
00491 }
00492 
00493 CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName)
00494 {
00495        static const char* sDisplayName = "xpt Linker";
00496        *displayName = sDisplayName;
00497        return cwNoErr;
00498 }
00499 
00500 CWPLUGIN_ENTRY(CWPlugin_GetPanelList)(const CWPanelList** panelList)
00501 {
00502        // +++Turn this on when the sample panel has been converted!
00503        static const char* sPanelName = kXPIDLPanelName;
00504        static CWPanelList sPanelList = { kCurrentCWPanelListVersion, 1, &sPanelName };
00505        
00506        *panelList = &sPanelList;
00507        
00508        return cwNoErr;
00509 }
00510 
00511 CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList)
00512 {
00513        static CWDataType sCPU = '****';
00514        static CWDataType sOS = '****';
00515        static CWTargetList sTargetList = { kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS };
00516        
00517        *targetList = &sTargetList;
00518        
00519        return cwNoErr;
00520 }
00521 
00522 CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList)
00523 {
00524        static CWExtensionMapping sExtension = { 'MMCH', ".xpt", 0 };
00525        static CWExtMapList sExtensionMapList = { kCurrentCWExtMapListVersion, 1, &sExtension };
00526        
00527        *defaultMappingList = &sExtensionMapList;
00528        
00529        return cwNoErr;
00530 }
00531 
00532 CWPLUGIN_ENTRY (CWPlugin_GetFamilyList)(const CWFamilyList** familyList)
00533 {
00534        static CWFamily sFamily = { 'XIDL', "xpidl Settings" };
00535        static CWFamilyList sFamilyList = { kCurrentCWFamilyListVersion, 0, &sFamily };
00536        
00537        *familyList = &sFamilyList;
00538        
00539        return cwNoErr;
00540 }
00541 
00542 #if CW_USE_PRAGMA_EXPORT
00543 #pragma export off
00544 #endif
00545 
00546 #endif