gnucap-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnucap-devel] Enhanced "attach" module.


From: al davis
Subject: [Gnucap-devel] Enhanced "attach" module.
Date: Thu, 22 Feb 2007 00:02:48 -0500
User-agent: KMail/1.9.5

Two issues with plugins have come up ...

1. If a plugin uses inhertance, deriving from a class in another 
plugin, they must be linked together into a single .so file.  
For example, d_bjt inherits from d_diode, and there is a 
hierarchy in the d_mos files. 

To use d_bjt as a plugin, either d_diode must have been linked 
into the core at compile time, or both d_diode and d_bjt must 
be linked into the same .so when building the plugin.  If I 
make them separate, d_bjt will not recognize d_diode.

To make it work when they are separate, the symbols in d_diode 
must be made public.  Usually, this is a bad idea, but there 
are times when you need it.  This is accomplished by passing a 
different flag to dlopen.

A new version of c_attach.cc, enclosed here, adds an 
option "public" to accomplish this.

2. If a plugin has unresolved references, it will not install.  
You will get a message when you "attach".  Usually, this is 
what is wanted, but there are times when it is appropriate to 
use an incomplete plugin.  One example of this is that some of 
the Spice model plugins fail because of a missing function that 
is only used for distortion analysis.  If you don't need 
distortion analysis it would be nice to be able to use the rest 
of it.

By passing another flag to dlopen, symbol binding is deferred 
until you actually need it, which could be never.

The new version of c_attach.cc, enclosed here, adds an 
option "lazy" to accomplish this.


You can replace the file c_attach.cc in the distribution with 
this one, or you can compile and attach it as a plugin.

Do this:
g++ -fPIC -shared -o c_attach.so c_attach.cc
to make the plugin "c_attach.so".

Then attach it:  "attach ./c_attach.so".
This will replace the built-in command with the new one.

If you want to keep it as a plugin, but want it automatically loaded,
put ".attach c_attach.so" (with the correct path) in your .gnucaprc .

File c_attach.cc follows:
===========================
/*$Id: c_attach.cc,v 26.15 2007/02/18 09:52:30 al Exp $ -*- C++ -*-
 * Copyright (C) 2007 Albert Davis
 * Author: Albert Davis <address@hidden>
 *
 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
 *
 * 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *------------------------------------------------------------------
 */
//testing=informal
#include "ap.h"
#include "e_cardlist.h"
#include "c_comand.h"
#include "l_dispatcher.h"
extern DISPATCHER<CMD> command_dispatcher;
/*--------------------------------------------------------------------------*/
namespace {
/*--------------------------------------------------------------------------*/
std::map<const std::string, void*> attach_list;
/*--------------------------------------------------------------------------*/
class CMD_ATTACH : public CMD {
public:
  void operator()(CS& cmd)const
  {
    int here = cmd.cursor();
    int scope = RTLD_LOCAL;
    int check = RTLD_NOW;
    // RTLD_NOW means to resolve symbols on loading
    // RTLD_LOCAL means symbols defined in a plugin are local
    do {
      if (cmd.icmatch("PUBLIC")) {
        scope = RTLD_GLOBAL;
        // RTLD_GLOBAL means symbols defined in a plugin are global
        // Use this when a plugin depends on another.
      }else if (cmd.icmatch("LAZY")) {
        check = RTLD_LAZY;
        // RTLD_LAZY means to defer resolving symbols until needed
        // Use when a plugin will not load because of unresolved symbols,
        // but it may work without it.
      }else{
      }
    } while (cmd.more() && !cmd.stuck(&here));

    std::string s;
    cmd >> s;
    
    void* handle = attach_list[s];
    if (handle) {
      if (CARD_LIST::card_list.is_empty()) {
        cmd.warn(bDANGER, here, "already loaded, replacing");
        dlclose(handle);
        attach_list[s] = NULL;
      }else{
        cmd.warn(bERROR, here,
                 "already loaded, cannot replace when there is a circuit\n");
      }
    }else{
    }
    handle = dlopen(s.c_str(), check | scope);
    if (handle) {
      attach_list[s] = handle;
    }else{
      cmd.warn(bERROR, here, dlerror());
    }
  }
} p1;
DISPATCHER<CMD>::INSTALL d1(&command_dispatcher, "attach", &p1);
/*--------------------------------------------------------------------------*/
class CMD_DETACH : public CMD {
public:
  void operator()(CS& cmd)const
  {
    if (CARD_LIST::card_list.is_empty()) {
      int here = cmd.cursor();
      std::string s;
      cmd >> s;
      
      void* handle = attach_list[s];
      if (handle) {
        dlclose(handle);
        attach_list[s] = NULL;
      }else{
        cmd.warn(bERROR, here, "plugin not attached");
      }
    }else{
      cmd.warn(bERROR, "detach prohibited when there is a circuit\n");
    }
  }
} p2;
DISPATCHER<CMD>::INSTALL d2(&command_dispatcher, "detach", &p2);
/*--------------------------------------------------------------------------*/
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]