Support env variables in spice library paths.

Also removes a bunch of std::string stuff from the file handling in the
simulator.  All our file handling, env variable expansion, project path,
etc. stuff is wxString based, and jumping through std::string in between
just makes it more complex and increases the potential bug surface.

Also fixes a bug where you'd get two error messages when a spice model
library wasn't found.

Also fixes a bug where you'd get a spice model library not found error
when the text field was empty.

Also fixes a bug where we'd try to absolutize a path starting with an
unresolved text or environment variable.  If the path starts with a
variable it's probably absolute, and tacking on the project path in the
error message just obfuscates things.

Fixes https://gitlab.com/kicad/code/kicad/issues/13082
This commit is contained in:
Jeff Young 2022-12-07 15:02:35 +00:00
parent 5aa204e194
commit b15913bd53
16 changed files with 111 additions and 103 deletions

View File

@ -264,7 +264,7 @@ wxString KIwxExpandEnvVars( const wxString& str, const PROJECT* aProject )
}
const wxString ExpandEnvVarSubstitutions( const wxString& aString, PROJECT* aProject )
const wxString ExpandEnvVarSubstitutions( const wxString& aString, const PROJECT* aProject )
{
// wxGetenv( wchar_t* ) is not re-entrant on linux.
// Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),

View File

@ -306,6 +306,11 @@ const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const
{
wxFileName fn = aFileName;
// Paths which start with an unresolved variable reference are more likely to be
// absolute than relative.
if( aFileName.StartsWith( wxT( "${" ) ) )
return aFileName;
if( !fn.IsAbsolute() )
{
wxString pro_dir = wxPathOnly( GetProjectFullName() );

View File

@ -55,7 +55,8 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
m_scintillaTricks( nullptr ),
m_wasCodePreviewUpdated( true ),
m_firstCategory( nullptr ),
m_prevParamGridSelection( nullptr )
m_prevParamGridSelection( nullptr ),
m_inKillFocus( false )
{
m_modelNameCombobox->SetValidator( m_modelNameValidator );
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
@ -262,7 +263,7 @@ bool DIALOG_SIM_MODEL<T>::TransferDataFromWindow()
if( ( library() && m_useLibraryModelRadioButton->GetValue() ) || isIbisLoaded() )
{
path = library()->GetFilePath();
path = m_libraryPathText->GetValue();
wxFileName fn( path );
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
@ -618,23 +619,16 @@ void DIALOG_SIM_MODEL<T>::loadLibrary( const wxString& aLibraryPath, bool aForce
if( !aForceReload && libraries.size() >= 1 && libraries.begin()->first == aLibraryPath )
return;
DIALOG_IBIS_PARSER_REPORTER dlg( this );
dlg.m_messagePanel->Clear();
bool tryingToLoadIbis = false;
if( aLibraryPath.EndsWith( ".ibs" ) )
tryingToLoadIbis = true;
try
{
m_libraryModelsMgr.SetLibrary( std::string( aLibraryPath.ToUTF8() ),
&dlg.m_messagePanel->Reporter() );
m_libraryModelsMgr.CreateLibrary( aLibraryPath, &dlg.m_messagePanel->Reporter() );
}
catch( const IO_ERROR& e )
{
if( tryingToLoadIbis )
if( dlg.m_messagePanel->Reporter().HasMessage() )
{
dlg.m_messagePanel->Flush();
dlg.ShowQuasiModal();
@ -976,11 +970,9 @@ void DIALOG_SIM_MODEL<T>::onLibraryPathTextEnter( wxCommandEvent& aEvent )
if( m_useLibraryModelRadioButton->GetValue() )
{
wxString path = m_libraryPathText->GetValue();
wxFileName fn( path );
if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
path = fn.GetFullPath();
if( !path.IsEmpty() )
{
try
{
loadLibrary( path );
@ -992,13 +984,33 @@ void DIALOG_SIM_MODEL<T>::onLibraryPathTextEnter( wxCommandEvent& aEvent )
}
}
}
}
template <typename T>
void DIALOG_SIM_MODEL<T>::onLibraryPathText( wxCommandEvent& aEvent )
{
}
template <typename T>
void DIALOG_SIM_MODEL<T>::onLibraryPathTextSetFocus( wxFocusEvent& aEvent )
{
}
template <typename T>
void DIALOG_SIM_MODEL<T>::onLibraryPathTextKillFocus( wxFocusEvent& aEvent )
{
if( !m_inKillFocus )
{
m_inKillFocus = true;
wxCommandEvent dummy;
onLibraryPathTextEnter( dummy );
m_inKillFocus = false;
}
}

View File

@ -114,8 +114,10 @@ private:
int getModelPinIndex( const wxString& aModelPinString ) const;
void onRadioButton( wxCommandEvent& aEvent ) override;
void onLibraryPathText( wxCommandEvent& aEvent ) override;
void onLibraryPathTextEnter( wxCommandEvent& aEvent ) override;
void onLibraryPathTextKillFocus( wxFocusEvent& aEvent ) override;
void onLibraryPathTextSetFocus( wxFocusEvent& aEvent ) override;
void onBrowseButtonClick( wxCommandEvent& aEvent ) override;
void onModelNameCombobox( wxCommandEvent& aEvent ) override;
void onModelNameComboboxKillFocus( wxFocusEvent& event ) override;
@ -157,6 +159,8 @@ private:
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
wxPGProperty* m_prevParamGridSelection;
bool m_inKillFocus;
};
#endif /* DIALOG_SIM_MODEL_H */

View File

@ -281,8 +281,9 @@ DIALOG_SIM_MODEL_BASE::DIALOG_SIM_MODEL_BASE( wxWindow* parent, wxWindowID id, c
m_useLibraryModelRadioButton->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onRadioButton ), NULL, this );
m_pathLabel->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathLabelUpdate ), NULL, this );
m_libraryPathText->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextKillFocus ), NULL, this );
m_libraryPathText->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextSetFocus ), NULL, this );
m_libraryPathText->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathText ), NULL, this );
m_libraryPathText->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextEnter ), NULL, this );
m_libraryPathText->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathUpdate ), NULL, this );
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonClick ), NULL, this );
m_browseButton->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
m_modelNameLabel->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onModelNameLabelUpdate ), NULL, this );
@ -322,8 +323,9 @@ DIALOG_SIM_MODEL_BASE::~DIALOG_SIM_MODEL_BASE()
m_useLibraryModelRadioButton->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onRadioButton ), NULL, this );
m_pathLabel->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathLabelUpdate ), NULL, this );
m_libraryPathText->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextKillFocus ), NULL, this );
m_libraryPathText->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextSetFocus ), NULL, this );
m_libraryPathText->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathText ), NULL, this );
m_libraryPathText->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathTextEnter ), NULL, this );
m_libraryPathText->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onLibraryPathUpdate ), NULL, this );
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonClick ), NULL, this );
m_browseButton->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onBrowseButtonUpdate ), NULL, this );
m_modelNameLabel->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_SIM_MODEL_BASE::onModelNameLabelUpdate ), NULL, this );

View File

@ -407,8 +407,9 @@
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnKillFocus">onLibraryPathTextKillFocus</event>
<event name="OnSetFocus">onLibraryPathTextSetFocus</event>
<event name="OnText">onLibraryPathText</event>
<event name="OnTextEnter">onLibraryPathTextEnter</event>
<event name="OnUpdateUI">onLibraryPathUpdate</event>
</object>
</object>
<object class="sizeritem" expanded="1">

View File

@ -87,8 +87,9 @@ class DIALOG_SIM_MODEL_BASE : public DIALOG_SHIM
virtual void onRadioButton( wxCommandEvent& event ) { event.Skip(); }
virtual void onLibraryPathLabelUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onLibraryPathTextKillFocus( wxFocusEvent& event ) { event.Skip(); }
virtual void onLibraryPathTextSetFocus( wxFocusEvent& event ) { event.Skip(); }
virtual void onLibraryPathText( wxCommandEvent& event ) { event.Skip(); }
virtual void onLibraryPathTextEnter( wxCommandEvent& event ) { event.Skip(); }
virtual void onLibraryPathUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onBrowseButtonClick( wxCommandEvent& event ) { event.Skip(); }
virtual void onBrowseButtonUpdate( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onModelNameLabelUpdate( wxUpdateUIEvent& event ) { event.Skip(); }

View File

@ -359,7 +359,7 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives( unsigned aNetlistOptions, REPORTER&
try
{
m_libMgr.CreateLibrary( path );
m_libMgr.CreateLibrary( path, &aReporter );
}
catch( const IO_ERROR& e )
{
@ -408,36 +408,33 @@ void NETLIST_EXPORTER_SPICE::readModel( SCH_SHEET_PATH& aSheet, SCH_SYMBOL& aSym
if( auto rawSpiceModel = dynamic_cast<const SIM_MODEL_RAW_SPICE*>( aItem.model ) )
{
int libParamIndex = static_cast<int>( SIM_MODEL_RAW_SPICE::SPICE_PARAM::LIB );
std::string path = rawSpiceModel->GetParam( libParamIndex ).value->ToString();
wxString path = rawSpiceModel->GetParam( libParamIndex ).value->ToString();
if( path != "" )
if( !path.IsEmpty() )
m_rawIncludes.insert( path );
}
else if( auto kibisModel = dynamic_cast<const SIM_MODEL_KIBIS*>( aItem.model ) )
{
wxFileName cacheDir;
cacheDir.AssignDir( PATHS::GetUserCachePath() );
cacheDir.AppendDir( wxT( "ibis" ) );
wxFileName cacheFn;
cacheFn.AssignDir( PATHS::GetUserCachePath() );
cacheFn.AppendDir( wxT( "ibis" ) );
cacheFn.SetFullName( aSymbol.GetRef( &aSheet ) + wxT( ".cache" ) );
std::string libraryPath = fmt::format( "{}/{}.cache",
std::string( cacheDir.GetPath() ),
std::string( aSymbol.GetRef( &aSheet ) ) );
wxFile cacheFile( libraryPath, wxFile::write );
wxFile cacheFile( cacheFn.GetFullPath(), wxFile::write );
if( !cacheFile.IsOpened() )
{
DisplayErrorMessage( nullptr,
wxString::Format( _( "Could not open file '%s' to write IBIS model" ),
libraryPath ) );
DisplayErrorMessage( nullptr, wxString::Format( _( "Could not open file '%s' to write "
"IBIS model" ),
cacheFn.GetFullPath() ) );
}
auto spiceGenerator = static_cast<const SPICE_GENERATOR_KIBIS&>( kibisModel->SpiceGenerator() );
std::string modelData = spiceGenerator.IbisDevice(
aItem, std::string( m_schematic->Prj().GetProjectPath().c_str() ),
std::string( cacheDir.GetPath( wxPATH_GET_SEPARATOR ) ).c_str() );
std::string modelData = spiceGenerator.IbisDevice( aItem, m_schematic->Prj(),
cacheFn.GetPath( wxPATH_GET_SEPARATOR ) );
cacheFile.Write( wxString( modelData ) );
m_rawIncludes.insert( libraryPath );
m_rawIncludes.insert( cacheFn.GetFullPath() );
}
}
@ -464,7 +461,7 @@ void NETLIST_EXPORTER_SPICE::readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& a
void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
const std::string& aPath )
const wxString& aPath )
{
// First, expand env vars, if any.
wxString expandedPath = ExpandEnvVarSubstitutions( aPath, &m_schematic->Prj() );
@ -495,13 +492,13 @@ void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
{
for( auto&& [path, library] : m_libMgr.GetLibraries() )
for( auto& [path, library] : m_libMgr.GetLibraries() )
{
if( dynamic_cast<const SIM_LIBRARY_SPICE*>( &library.get() ) )
writeInclude( aFormatter, aNetlistOptions, path );
}
for( const std::string& path : m_rawIncludes )
for( const wxString& path : m_rawIncludes )
writeInclude( aFormatter, aNetlistOptions, path );
}

View File

@ -144,7 +144,7 @@ private:
void readPinNetNames( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& aNcCounter );
void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
const std::string& aPath );
const wxString& aPath );
void writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions );
void writeModels( OUTPUTFORMATTER& aFormatter );
@ -156,7 +156,7 @@ private:
std::string m_title; ///< Spice simulation title found in the schematic sheet
std::vector<std::string> m_directives; ///< Spice directives found in the schematic sheet
//std::map<std::string, std::unique_ptr<SIM_LIBRARY>> m_libraries; ///< Spice libraries
std::set<std::string> m_rawIncludes; ///< include directives found in symbols
std::set<wxString> m_rawIncludes; ///< include directives found in symbols
std::set<std::string> m_nets;
std::list<SPICE_ITEM> m_items; ///< Items representing schematic symbols in Spice world
};

View File

@ -24,6 +24,7 @@
#include <pgm_base.h>
#include <string>
#include <common.h>
#include <sch_symbol.h>
// Include simulator headers after wxWidgets headers to avoid conflicts with Windows headers
@ -33,7 +34,6 @@
#include <sim/sim_model.h>
#include <sim/sim_model_ideal.h>
SIM_LIB_MGR::SIM_LIB_MGR( const PROJECT& aPrj ) : m_project( aPrj )
{
}
@ -46,26 +46,18 @@ void SIM_LIB_MGR::Clear()
}
SIM_LIBRARY& SIM_LIB_MGR::CreateLibrary( const std::string& aLibraryPath, REPORTER* aReporter )
SIM_LIBRARY& SIM_LIB_MGR::CreateLibrary( const wxString& aLibraryPath, REPORTER* aReporter )
{
std::string absolutePath = std::string( m_project.AbsolutePath( aLibraryPath ).ToUTF8() );
auto it =
m_libraries.try_emplace( aLibraryPath, SIM_LIBRARY::Create( absolutePath, aReporter ) )
.first;
return *it->second;
}
SIM_LIBRARY& SIM_LIB_MGR::SetLibrary( const std::string& aLibraryPath, REPORTER* aReporter )
{
std::string absolutePath = std::string( m_project.AbsolutePath( aLibraryPath ).ToUTF8() );
wxString path = ExpandEnvVarSubstitutions( aLibraryPath, &m_project );
wxString absolutePath = m_project.AbsolutePath( path );
// May throw an exception.
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( absolutePath, aReporter );
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( m_project.AbsolutePath( path ),
aReporter );
Clear();
m_libraries[aLibraryPath] = std::move( library );
return *m_libraries.at( aLibraryPath );
m_libraries[path] = std::move( library );
return *m_libraries.at( path );
}
@ -153,18 +145,18 @@ template SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::vector<LIB_FIEL
template <typename T>
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const std::string& aLibraryPath,
SIM_LIBRARY::MODEL SIM_LIB_MGR::CreateModel( const wxString& aLibraryPath,
const std::string& aBaseModelName,
const std::vector<T>& aFields,
int aSymbolPinCount )
{
std::string absolutePath = std::string( m_project.AbsolutePath( aLibraryPath ).ToUTF8() );
wxString path = ExpandEnvVarSubstitutions( aLibraryPath, &m_project );
wxString absolutePath = m_project.AbsolutePath( path );
SIM_LIBRARY* library = nullptr;
try
{
auto it = m_libraries.try_emplace( aLibraryPath,
SIM_LIBRARY::Create( absolutePath ) ).first;
auto it = m_libraries.try_emplace( path, SIM_LIBRARY::Create( absolutePath ) ).first;
library = &*it->second;
}
catch( const IO_ERROR& e )
@ -203,9 +195,9 @@ void SIM_LIB_MGR::SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel )
}
std::map<std::string, std::reference_wrapper<const SIM_LIBRARY>> SIM_LIB_MGR::GetLibraries() const
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> SIM_LIB_MGR::GetLibraries() const
{
std::map<std::string, std::reference_wrapper<const SIM_LIBRARY>> libraries;
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> libraries;
for( auto& [path, library] : m_libraries )
libraries.try_emplace( path, *library );

View File

@ -45,8 +45,7 @@ public:
void Clear();
SIM_LIBRARY& CreateLibrary( const std::string& aLibraryPath, REPORTER* aReporter = nullptr );
SIM_LIBRARY& SetLibrary( const std::string& aLibraryPath, REPORTER* aReporter = nullptr );
SIM_LIBRARY& CreateLibrary( const wxString& aLibraryPath, REPORTER* aReporter );
SIM_MODEL& CreateModel( SIM_MODEL::TYPE aType, int aSymbolPinCount );
@ -63,19 +62,17 @@ public:
SIM_LIBRARY::MODEL CreateModel( const std::vector<T>& aFields, int aSymbolPinCount );
template <typename T>
SIM_LIBRARY::MODEL CreateModel( const std::string& aLibraryPath,
const std::string& aBaseModelName,
const std::vector<T>& aFields,
int aSymbolPinCount );
SIM_LIBRARY::MODEL CreateModel( const wxString& aLibraryPath, const std::string& aBaseModelName,
const std::vector<T>& aFields, int aSymbolPinCount );
void SetModel( int aIndex, std::unique_ptr<SIM_MODEL> aModel );
std::map<std::string, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
std::map<wxString, std::reference_wrapper<const SIM_LIBRARY>> GetLibraries() const;
std::vector<std::reference_wrapper<SIM_MODEL>> GetModels() const;
private:
const PROJECT& m_project;
std::map<std::string, std::unique_ptr<SIM_LIBRARY>> m_libraries;
std::map<wxString, std::unique_ptr<SIM_LIBRARY>> m_libraries;
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
};

View File

@ -27,18 +27,17 @@
#include <sim/sim_library_spice.h>
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( std::string aFilePath, REPORTER* aReporter )
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter )
{
std::unique_ptr<SIM_LIBRARY> library;
wxString wxaFilePath( aFilePath );
if( wxaFilePath.EndsWith( ".ibs" ) )
if( aFilePath.EndsWith( ".ibs" ) )
library = std::make_unique<SIM_LIBRARY_KIBIS>();
else
library = std::make_unique<SIM_LIBRARY_SPICE>();
library->m_reporter = aReporter;
library->ReadFile( aFilePath );
library->ReadFile( std::string( aFilePath.c_str() ) );
return library;
}

View File

@ -52,7 +52,7 @@ public:
* @param aReporter The reporter the library reports to
* @return The library loaded in a newly constructed object.
*/
static std::unique_ptr<SIM_LIBRARY> Create( std::string aFilePath,
static std::unique_ptr<SIM_LIBRARY> Create( const wxString& aFilePath,
REPORTER* aReporter = nullptr );
/**

View File

@ -24,7 +24,7 @@
#include <sim/kibis/kibis.h>
#include <sim/sim_model_kibis.h>
#include <sim/sim_library_kibis.h>
#include <paths.h>
#include <common.h>
#include <fmt/core.h>
#include <wx/filename.h>
#include <kiway.h>
@ -58,8 +58,8 @@ std::vector<std::string> SPICE_GENERATOR_KIBIS::CurrentNames( const SPICE_ITEM&
}
std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const std::string aCwd,
const std::string aCacheDir ) const
std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
const wxString& aCacheDir ) const
{
std::string ibisLibFilename = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::LIBRARY_FIELD );
std::string ibisCompName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY::NAME_FIELD );
@ -67,13 +67,11 @@ std::string SPICE_GENERATOR_KIBIS::IbisDevice( const SPICE_ITEM& aItem, const st
std::string ibisModelName = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::MODEL_FIELD );
bool diffMode = SIM_MODEL::GetFieldValue( &aItem.fields, SIM_LIBRARY_KIBIS::DIFF_FIELD ) == "1";
wxFileName libPath = wxFileName( wxString( ibisLibFilename ) );
wxString path = ExpandEnvVarSubstitutions( ibisLibFilename, &aProject );
wxString absolutePath = aProject.AbsolutePath( path );
if( !libPath.IsAbsolute() )
libPath.MakeAbsolute( aCwd );
KIBIS kibis( std::string( libPath.GetFullPath().c_str() ) );
kibis.m_cacheDir = aCacheDir;
KIBIS kibis( std::string( absolutePath.c_str() ) );
kibis.m_cacheDir = std::string( aCacheDir.c_str() );
if( !kibis.m_valid )
{

View File

@ -41,8 +41,8 @@ public:
std::string ModelLine( const SPICE_ITEM& aItem ) const override;
std::vector<std::string> CurrentNames( const SPICE_ITEM& aItem ) const override;
std::string IbisDevice( const SPICE_ITEM& aItem, const std::string aCwd,
const std::string aCacheDir ) const;
std::string IbisDevice( const SPICE_ITEM& aItem, const PROJECT& aProject,
const wxString& aCacheDir ) const;
protected:
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> GetInstanceParams() const override;

View File

@ -76,7 +76,7 @@ bool EnsureFileDirectoryExists( wxFileName* aTargetFullFileName,
* @param aString a string containing (perhaps) references to env var
* @return the expanded environment variable.
*/
const wxString ExpandEnvVarSubstitutions( const wxString& aString, PROJECT* aProject );
const wxString ExpandEnvVarSubstitutions( const wxString& aString, const PROJECT* aProject );
/**
* Expand '${var-name}' templates in text. The LocalResolver is given first crack at it,