KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_import_reconciler.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <map>
23#include <set>
24#include <utility>
25
26#include <wx/filefn.h>
27#include <wx/filename.h>
28
30#include <lib_id.h>
31#include <lib_symbol.h>
32#include <project.h>
33#include <project_sch.h>
34#include <reporter.h>
35#include <schematic.h>
36#include <sch_pin.h>
37#include <sch_screen.h>
38#include <sch_symbol.h>
40#include <io/io_mgr.h>
41#include <sch_io/sch_io.h>
42#include <sch_io/sch_io_mgr.h>
46
47
49 const wxString& aProjectPath,
50 REPORTER& aReporter ) :
51 m_adapter( aAdapter ),
52 m_projectPath( aProjectPath ),
53 m_reporter( aReporter )
54{
55}
56
57
58namespace
59{
60// every screen once, so a sheet instantiated many times does not re-walk its symbols
61std::vector<SCH_SYMBOL*> placedSymbols( SCHEMATIC* aSchematic )
62{
63 std::vector<SCH_SYMBOL*> symbols;
64 SCH_SCREENS screens( aSchematic->Root() );
65
66 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
67 {
68 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
69 symbols.push_back( static_cast<SCH_SYMBOL*>( item ) );
70 }
71
72 return symbols;
73}
74
75
76// structural signature, flags same-name placed instances that differ
77wxString placedSignature( const SCH_SYMBOL* aSymbol )
78{
79 const std::unique_ptr<LIB_SYMBOL>& part = aSymbol->GetLibSymbolRef();
80
81 if( !part )
82 return wxEmptyString;
83
84 return wxString::Format( wxS( "%d:%d" ), part->GetPinCount(), part->GetUnitCount() );
85}
86
87
88// lookup that tolerates an unreadable or absent library
89LIB_SYMBOL* loadSymbol( SYMBOL_LIBRARY_ADAPTER& aAdapter, const wxString& aNickname,
90 const wxString& aName )
91{
92 try
93 {
94 return aAdapter.LoadSymbol( aNickname, aName );
95 }
96 catch( const IO_ERROR& )
97 {
98 return nullptr;
99 }
100}
101
102
103std::multiset<wxString> pinNumbers( const LIB_SYMBOL& aSymbol )
104{
105 std::multiset<wxString> numbers;
106
107 for( const SCH_PIN* pin : aSymbol.GetPins() )
108 numbers.insert( pin->GetNumber() );
109
110 return numbers;
111}
112
113
114// two tools never draw a part identically, so equivalence is the electrical interface
115bool sameInterface( const LIB_SYMBOL& aLhs, const LIB_SYMBOL& aRhs )
116{
117 return aLhs.GetUnitCount() == aRhs.GetUnitCount() && pinNumbers( aLhs ) == pinNumbers( aRhs );
118}
119
120
121// reuse existing row/file only if prior import-managed cache
122bool isManagedCache( const LIBRARY_TABLE_ROW* aRow )
123{
124 return aRow && aRow->GetOptionsMap().count( IMPORT_PROJ_PROPS::MANAGED_CACHE_KEY ) > 0;
125}
126}
127
128
131 std::vector<std::unique_ptr<LIB_SYMBOL>> aDefinitions,
132 const wxString& aCacheNickname,
133 const std::vector<wxString>& aSourceLibNicknames )
134{
136
137 if( !aSchematic )
138 return result;
139
140 // source nickname + item name, so same-name parts from different libraries stay split
141 using SOURCE_KEY = std::pair<wxString, wxString>;
142
143 std::map<SOURCE_KEY, LIB_SYMBOL*> defByKey;
144 std::map<wxString, std::vector<LIB_SYMBOL*>> defsByName;
145
146 for( const std::unique_ptr<LIB_SYMBOL>& def : aDefinitions )
147 {
148 wxString name = def->GetLibId().GetUniStringLibItemName();
149
150 if( name.IsEmpty() )
151 name = def->GetName();
152
153 if( name.IsEmpty() )
154 continue;
155
156 defByKey.emplace( SOURCE_KEY( def->GetLibId().GetUniStringLibNickname(), name ), def.get() );
157 defsByName[name].push_back( def.get() );
158 }
159
160 // definitions can carry a different nickname from the placed symbols, so a unique name still
161 // matches, but an ambiguous one must not
162 auto findDef = [&]( const wxString& aNick, const wxString& aName ) -> LIB_SYMBOL*
163 {
164 if( auto it = defByKey.find( SOURCE_KEY( aNick, aName ) ); it != defByKey.end() )
165 return it->second;
166
167 auto byName = defsByName.find( aName );
168
169 if( byName == defsByName.end() || byName->second.size() != 1 )
170 return nullptr;
171
172 return byName->second.front();
173 };
174
175 // preload source libs before membership queries
176 for( const wxString& nick : aSourceLibNicknames )
177 {
178 if( m_adapter.GetRow( nick ) )
179 m_adapter.LoadOne( nick );
180 }
181
182 std::set<wxString> provenance( aSourceLibNicknames.begin(), aSourceLibNicknames.end() );
183
184 // resolve one source lib, empty if none or ambiguous
185 auto resolveSource = [&]( const SCH_SYMBOL* aSymbol, const wxString& aName ) -> wxString
186 {
187 std::vector<wxString> candidates;
188 wxString ownNick = aSymbol->GetLibId().GetUniStringLibNickname();
189
190 if( !ownNick.IsEmpty() )
191 candidates.push_back( ownNick );
192
193 for( const wxString& nick : aSourceLibNicknames )
194 {
195 if( nick != ownNick )
196 candidates.push_back( nick );
197 }
198
199 std::vector<wxString> matches;
200
201 for( const wxString& nick : candidates )
202 {
203 if( !m_adapter.GetRow( nick ) )
204 continue;
205
206 LIB_SYMBOL* candidate = loadSymbol( m_adapter, nick, aName );
207
208 if( !candidate )
209 continue;
210
211 // A nickname the importer emitted is not provenance. An unrelated library that
212 // happens to carry the name must not swallow the imported definition, so it takes the
213 // link only when it holds the same part.
214 if( !provenance.count( nick ) )
215 {
216 LIB_SYMBOL* def = findDef( ownNick, aName );
217
218 if( !def || !sameInterface( *candidate, *def ) )
219 continue;
220 }
221
222 matches.push_back( nick );
223 }
224
225 return matches.size() == 1 ? matches.front() : wxString( wxEmptyString );
226 };
227
228 std::vector<SCH_SYMBOL*> symbols = placedSymbols( aSchematic );
229
230 // per-instance target, empty target = cache-bound
231 std::map<SOURCE_KEY, wxString> targetByKey;
232 std::set<SOURCE_KEY> cacheKeys;
233 std::map<SOURCE_KEY, std::vector<SCH_SYMBOL*>> instancesByKey;
234
235 for( SCH_SYMBOL* symbol : symbols )
236 {
237 wxString name = symbol->GetLibId().GetUniStringLibItemName();
238
239 if( name.IsEmpty() )
240 continue;
241
242 SOURCE_KEY key( symbol->GetLibId().GetUniStringLibNickname(), name );
243
244 instancesByKey[key].push_back( symbol );
245
246 if( targetByKey.count( key ) )
247 continue;
248
249 wxString sourceNick = resolveSource( symbol, name );
250 targetByKey[key] = sourceNick;
251
252 if( sourceNick.IsEmpty() )
253 cacheKeys.insert( key );
254 }
255
256 // one library cannot hold two items of the same name, so a collision takes a suffix
257 std::set<wxString> takenNames;
258
259 auto uniqueName = [&takenNames]( const wxString& aName )
260 {
261 wxString candidate = aName;
262
263 for( int suffix = 1; !takenNames.insert( candidate ).second; ++suffix )
264 candidate = wxString::Format( wxS( "%s_%d" ), aName, suffix );
265
266 return candidate;
267 };
268
269 // canonical def per cache key, fall back to the placed instance cache if importer gave none
270 std::map<wxString, LIB_SYMBOL*> cacheDefs;
271 std::map<SOURCE_KEY, wxString> cacheNameByKey;
272 std::map<const LIB_SYMBOL*, wxString> cacheNameByDef;
273 std::vector<std::unique_ptr<LIB_SYMBOL>> placedDefs;
274 std::vector<wxString> renameReports;
275
276 // a derived symbol extends its parent by name, which a rename can move
277 std::vector<std::pair<LIB_SYMBOL*, SOURCE_KEY>> parentFixups;
278
279 for( const SOURCE_KEY& key : cacheKeys )
280 {
281 const wxString& name = key.second;
282 LIB_SYMBOL* def = findDef( key.first, name );
283
284 if( !def )
285 {
286 const std::vector<SCH_SYMBOL*>& instances = instancesByKey[key];
287
288 if( instances.empty() || !instances.front()->GetLibSymbolRef() )
289 continue;
290
291 wxString firstSig = placedSignature( instances.front() );
292
293 for( auto it = instances.begin() + 1; it != instances.end(); ++it )
294 {
295 if( placedSignature( *it ) != firstSig )
296 {
297 m_reporter.Report( wxString::Format( _( "Imported symbol '%s' has conflicting "
298 "placed definitions; keeping the "
299 "first." ), name ),
301 break;
302 }
303 }
304
305 placedDefs.push_back(
306 std::make_unique<LIB_SYMBOL>( *instances.front()->GetLibSymbolRef() ) );
307 def = placedDefs.back().get();
308 }
309
310 // one definition serving several source libraries stays a single cache item
311 if( auto it = cacheNameByDef.find( def ); it != cacheNameByDef.end() )
312 {
313 cacheNameByKey[key] = it->second;
314 continue;
315 }
316
317 wxString cacheName = uniqueName( name );
318
319 cacheNameByDef[def] = cacheName;
320 cacheNameByKey[key] = cacheName;
321 cacheDefs[cacheName] = def;
322
323 if( !def->GetParentName().IsEmpty() )
324 parentFixups.emplace_back( def, SOURCE_KEY( key.first, def->GetParentName() ) );
325
326 if( cacheName != name )
327 {
328 renameReports.push_back(
329 wxString::Format( _( "Imported symbol '%s' from '%s' was renamed to '%s' "
330 "because another library supplies a different symbol of "
331 "that name." ), name, key.first, cacheName ) );
332 }
333 }
334
335 for( const auto& [def, parentKey] : parentFixups )
336 {
337 if( auto it = cacheNameByKey.find( parentKey ); it != cacheNameByKey.end() )
338 def->SetParentName( it->second );
339 }
340
341 if( !cacheDefs.empty() )
342 writeAndRegisterCache( aCacheNickname, cacheDefs, result );
343
344 // no rename happened if the cache did not publish
345 if( !result.m_cacheNickname.IsEmpty() )
346 {
347 for( const wxString& report : renameReports )
348 m_reporter.Report( report, RPT_SEVERITY_WARNING );
349 }
350
351 // re-point nicks to the resolved lib, cache-bound symbols also take their cache item name
352 for( SCH_SYMBOL* symbol : symbols )
353 {
354 LIB_ID libId = symbol->GetLibId();
355 wxString name = libId.GetUniStringLibItemName();
356
357 if( name.IsEmpty() )
358 continue;
359
360 SOURCE_KEY key( libId.GetUniStringLibNickname(), name );
361 auto it = targetByKey.find( key );
362
363 if( it == targetByKey.end() )
364 {
365 result.m_unresolved++;
366 continue;
367 }
368
369 // empty resolution = cache-bound, resolves only once the cache is published
370 if( it->second.IsEmpty() )
371 {
372 auto cacheName = cacheNameByKey.find( key );
373
374 if( result.m_cacheNickname.IsEmpty() || cacheName == cacheNameByKey.end() )
375 {
376 result.m_unresolved++;
377 continue;
378 }
379
380 libId.SetLibNickname( aCacheNickname );
381 libId.SetLibItemName( cacheName->second );
382 symbol->SetLibId( libId );
383 result.m_linkedToCache++;
384 }
385 else
386 {
387 libId.SetLibNickname( it->second );
388 symbol->SetLibId( libId );
389 result.m_linkedToSource++;
390 }
391 }
392
393 return result;
394}
395
396
398 const wxString& aCacheNickname, const std::map<wxString, LIB_SYMBOL*>& aCacheDefs,
400{
401 wxFileName finalFn( m_projectPath, aCacheNickname, FILEEXT::KiCadSymbolLibFileExtension );
402 wxString finalPath = finalFn.GetFullPath();
403 wxString tempPath = finalPath + wxS( ".tmp" );
404
405 // a nickname the user already owns is never repurposed, whatever its row points at
406 LIBRARY_TABLE_ROW* existingRow = m_adapter.GetRow( aCacheNickname ).value_or( nullptr );
407
408 if( existingRow && !isManagedCache( existingRow ) )
409 {
410 m_reporter.Report( wxString::Format( _( "A symbol library named '%s' is already "
411 "registered; leaving imported symbols "
412 "unresolved." ), aCacheNickname ),
414 return;
415 }
416
417 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
418
419 if( !pi )
420 {
421 m_reporter.Report( _( "Cannot reconcile imported symbols: no KiCad symbol writer." ),
423 return;
424 }
425
426 // best-effort cleanup, must not throw
427 auto safeDelete = [&pi]( const wxString& aPath )
428 {
429 try
430 {
431 pi->DeleteLibrary( aPath );
432 }
433 catch( const IO_ERROR& )
434 {
435 }
436 };
437
438 bool wrote = false;
439
440 try
441 {
442 if( wxFileExists( tempPath ) )
443 pi->DeleteLibrary( tempPath );
444
445 pi->CreateLibrary( tempPath );
446
447 // buffer the writes, the library is flushed once by SaveLibrary
448 std::map<std::string, UTF8> properties;
449 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, wxEmptyString );
450
451 for( const auto& [name, def] : aCacheDefs )
452 {
453 std::unique_ptr<LIB_SYMBOL> copy = std::make_unique<LIB_SYMBOL>( *def );
454
455 // the library is keyed by the symbol name, which SetLibId leaves alone
456 copy->SetName( name );
457
458 LIB_ID id = copy->GetLibId();
459
460 id.SetLibNickname( aCacheNickname );
461 copy->SetLibId( id );
462 pi->SaveSymbol( tempPath, std::move( copy ), &properties );
463 }
464
465 pi->SaveLibrary( tempPath );
466 wrote = true;
467 }
468 catch( const IO_ERROR& ioe )
469 {
470 m_reporter.Report( wxString::Format( _( "Error writing imported symbol cache '%s': %s" ),
471 aCacheNickname, ioe.What() ),
473 }
474
475 if( !wrote )
476 {
477 if( wxFileExists( tempPath ) )
478 safeDelete( tempPath );
479
480 return;
481 }
482
483 // publish temp->final, replace only a managed cache, never a user lib
484 if( wxFileExists( finalPath ) )
485 {
486 if( isManagedCache( existingRow ) )
487 {
488 safeDelete( finalPath );
489 }
490 else
491 {
492 m_reporter.Report( wxString::Format( _( "A library already exists at '%s'; leaving "
493 "imported symbols unresolved." ), finalPath ),
495 safeDelete( tempPath );
496 return;
497 }
498 }
499
500 if( !wxRenameFile( tempPath, finalPath, false ) )
501 {
502 m_reporter.Report( wxString::Format( _( "Could not publish imported symbol cache to "
503 "'%s'." ), finalPath ),
505 safeDelete( tempPath );
506 return;
507 }
508
509 // only claim the cache when its table row is registered, else LIB_IDs re-point to a dead nickname
510 if( !registerCacheRow( aCacheNickname ) )
511 return;
512
513 aResult.m_cacheNickname = aCacheNickname;
514 aResult.m_savedToCache = static_cast<int>( aCacheDefs.size() );
515}
516
517
518bool SYMBOL_IMPORT_RECONCILER::registerCacheRow( const wxString& aCacheNickname )
519{
520 std::optional<LIBRARY_TABLE*> tableOpt = m_adapter.ProjectTable();
521
522 if( !tableOpt || !*tableOpt )
523 {
524 m_reporter.Report( _( "Cannot register imported symbol cache: no project library "
525 "table." ), RPT_SEVERITY_ERROR );
526 return false;
527 }
528
529 LIBRARY_TABLE* table = *tableOpt;
530 wxString cacheFile = aCacheNickname + wxS( "." )
532 wxString uri = wxS( "${KIPRJMOD}/" ) + cacheFile;
533 LIBRARY_TABLE_ROW* row = table->HasRow( aCacheNickname )
534 ? table->Row( aCacheNickname ).value_or( nullptr )
535 : &table->InsertRow();
536
537 if( !row )
538 return false;
539
540 row->SetNickname( aCacheNickname );
541 row->SetURI( uri );
542 row->SetType( wxS( "KiCad" ) );
545
546 // an unsaved row is gone on restart, so the cache cannot be claimed
547 if( !table->Save() )
548 {
549 m_reporter.Report( _( "Error saving project symbol library table; imported symbols left "
550 "unresolved." ), RPT_SEVERITY_ERROR );
551 return false;
552 }
553
554 // load the cache so membership and later lookups resolve it
555 m_adapter.LoadOne( aCacheNickname );
556 return true;
557}
558
559
561ReconcileImportedSymbols( SCH_IO& aPlugin, SCHEMATIC& aSchematic, PROJECT& aProject,
562 const wxString& aSchematicPath,
563 const std::map<std::string, UTF8>* aProperties, REPORTER& aReporter )
564{
566 std::vector<std::unique_ptr<LIB_SYMBOL>> definitions;
567
568 try
569 {
570 for( LIB_SYMBOL* symbol : aPlugin.GetImportedCachedLibrarySymbols() )
571 definitions.emplace_back( symbol );
572 }
573 catch( const IO_ERROR& )
574 {
575 return result;
576 }
577
578 // Importers still writing their own project library during load (Eagle) must be left alone:
579 // with no definitions to interface-match, resolveSource would reject the library they just
580 // wrote and duplicate every symbol into the cache. Drop this once they all publish here.
581 if( definitions.empty() )
582 return result;
583
585
586 if( !adapter )
587 return result;
588
589 // manager pre-commits the cache nickname + source libs; standalone import derives from filename
590 wxString cacheNick;
591 std::vector<wxString> sourceLibs;
592 IMPORT_PROJ_PROPS::ReadSymbolProps( aProperties, cacheNick, sourceLibs );
593
594 if( cacheNick.IsEmpty() )
595 {
597 wxFileName( aSchematicPath ).GetName() );
598 }
599
600 SYMBOL_IMPORT_RECONCILER reconciler( *adapter, aProject.GetProjectPath(), aReporter );
601
602 // reconciliation failure must not abort the import
603 try
604 {
605 result = reconciler.Reconcile( &aSchematic, std::move( definitions ), cacheNick,
606 sourceLibs );
607 }
608 catch( const IO_ERROR& ioe )
609 {
610 aReporter.Report( wxString::Format( _( "Could not reconcile imported symbol libraries: "
611 "%s" ), ioe.What() ), RPT_SEVERITY_ERROR );
612 }
613
614 return result;
615}
const char * name
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
void SetOptions(const wxString &aOptions)
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
std::map< std::string, UTF8 > GetOptionsMap() const
void SetURI(const wxString &aUri)
void SetScope(LIBRARY_TABLE_SCOPE aScope)
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:124
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const wxString GetUniStringLibNickname() const
Definition lib_id.h:84
Define a library symbol object.
Definition lib_symbol.h:119
std::vector< SCH_PIN * > GetPins() const override
const wxString & GetParentName() const
Definition lib_symbol.h:985
int GetUnitCount() const override
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:63
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
Holds all the data relating to one schematic.
Definition schematic.h:148
SCH_SHEET & Root() const
Definition schematic.h:199
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Base class that schematic file and library loading and saving plugins should derive from.
Definition sch_io.h:60
virtual std::vector< LIB_SYMBOL * > GetImportedCachedLibrarySymbols()
Return the canonical symbol definitions produced by the last LoadSchematicFile().
Definition sch_io.cpp:76
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:165
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:758
Schematic symbol object.
Definition sch_symbol.h:75
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:183
Frame-independent, non-interactive service that reconciles the symbol-library references of a freshly...
bool registerCacheRow(const wxString &aCacheNickname)
Insert or refresh the project symbol-library-table row for the generated cache.
SYMBOL_IMPORT_RECONCILER(SYMBOL_LIBRARY_ADAPTER &aAdapter, const wxString &aProjectPath, REPORTER &aReporter=NULL_REPORTER::GetInstance())
SYMBOL_IMPORT_RECONCILE_RESULT Reconcile(SCHEMATIC *aSchematic, std::vector< std::unique_ptr< LIB_SYMBOL > > aDefinitions, const wxString &aCacheNickname, const std::vector< wxString > &aSourceLibNicknames)
Reconcile aSchematic against the importer definitions and the provenance source libraries.
SYMBOL_LIBRARY_ADAPTER & m_adapter
void writeAndRegisterCache(const wxString &aCacheNickname, const std::map< wxString, LIB_SYMBOL * > &aCacheDefs, SYMBOL_IMPORT_RECONCILE_RESULT &aResult)
Write the residual definitions into an atomically-published .kicad_sym and register its row.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
#define _(s)
static const std::string KiCadSymbolLibFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
void ReadSymbolProps(const std::map< std::string, UTF8 > *aProps, wxString &aCacheNickname, std::vector< wxString > &aSourceSymLibs)
Read the symbol-import coordination properties out of a properties map.
wxString ManagedCacheOption()
Options string identifying a library-table row as a generated import cache.
constexpr char MANAGED_CACHE_KEY[]
Library-table row option key marking a row as a generated import cache.
wxString MakeSymbolCacheNickname(const wxString &aStem)
Derive the generated symbol-cache nickname from a project or file stem.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
LIB_SYMBOL * loadSymbol(const wxString &aLibraryPath, nlohmann::json aFileData, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties)
Outcome of a post-import symbol-library reconciliation pass.
wxString m_cacheNickname
nickname of the generated cache, empty if none written
int m_savedToCache
distinct definitions written into the cache library
SYMBOL_IMPORT_RECONCILE_RESULT ReconcileImportedSymbols(SCH_IO &aPlugin, SCHEMATIC &aSchematic, PROJECT &aProject, const wxString &aSchematicPath, const std::map< std::string, UTF8 > *aProperties, REPORTER &aReporter)
Reconcile aSchematic against the definitions aPlugin retained while loading it.
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.
@ SCH_SYMBOL_T
Definition typeinfo.h:168
Definition of file extensions used in Kicad.