KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad.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 (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
31#include <wx/filename.h>
32#include <wx/log.h>
33#include <wx/app.h>
34#include <wx/stdpaths.h>
35#include <wx/msgdlg.h>
36#include <wx/cmdline.h>
37
38#include <env_vars.h>
39#include <file_history.h>
40#include <hotkeys_basic.h>
41#include <kiway.h>
42#include <macros.h>
43#include <paths.h>
44#include <richio.h>
47#include <systemdirsappend.h>
48#include <trace_helpers.h>
50#include <confirm.h>
51
52#include <git2.h>
53#include <stdexcept>
54
55#include "pgm_kicad.h"
56#include "kicad_manager_frame.h"
57
58#include <kiplatform/app.h>
60
61#ifdef KICAD_IPC_API
62#include <api/api_server.h>
63#endif
64
65// a dummy to quiet linking with EDA_BASE_FRAME::config();
66#include <kiface_base.h>
68{
69 // This function should never be called. It is only referenced from
70 // EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
71 // not to be actually called.
72 wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
73
74 throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
75}
76
77
79
81{
82 return program;
83}
84
85
87{
88 App().SetAppDisplayName( wxT( "KiCad" ) );
89
90#if defined(DEBUG)
91 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
92
93 if( !wxIsAbsolutePath( absoluteArgv0 ) )
94 {
95 wxLogError( wxT( "No meaningful argv[0]" ) );
96 return false;
97 }
98#endif
99
100 // Initialize the git library before trying to initialize individual programs
101 git_libgit2_init();
102
103 static const wxCmdLineEntryDesc desc[] = {
104 { wxCMD_LINE_OPTION, "f", "frame", "Frame to load", wxCMD_LINE_VAL_STRING, 0 },
105 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
106 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
107 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
108 };
109
110 wxCmdLineParser parser( App().argc, App().argv );
111 parser.SetDesc( desc );
112 parser.Parse( false );
113
114 FRAME_T appType = KICAD_MAIN_FRAME_T;
115
116 const struct
117 {
118 wxString name;
119 FRAME_T type;
120 } frameTypes[] = { { wxT( "pcb" ), FRAME_PCB_EDITOR },
121 { wxT( "fpedit" ), FRAME_FOOTPRINT_EDITOR },
122 { wxT( "sch" ), FRAME_SCH },
123 { wxT( "calc" ), FRAME_CALC },
124 { wxT( "bm2cmp" ), FRAME_BM2CMP },
125 { wxT( "ds" ), FRAME_PL_EDITOR },
126 { wxT( "gerb" ), FRAME_GERBER },
127 { wxT( "" ), FRAME_T_COUNT } };
128
129 wxString frameName;
130
131 if( parser.Found( "frame", &frameName ) )
132 {
133 appType = FRAME_T_COUNT;
134
135 for( const auto& it : frameTypes )
136 {
137 if( it.name == frameName )
138 appType = it.type;
139 }
140
141 if( appType == FRAME_T_COUNT )
142 {
143 wxLogError( wxT( "Unknown frame: %s" ), frameName );
144 // Clean up
145 OnPgmExit();
146 return false;
147 }
148 }
149
150 if( appType == KICAD_MAIN_FRAME_T )
151 {
153 }
154 else
155 {
157 }
158
159 bool skipPythonInit = false;
160
161 if( appType == FRAME_BM2CMP || appType == FRAME_PL_EDITOR || appType == FRAME_GERBER
162 || appType == FRAME_CALC )
163 skipPythonInit = true;
164
165 if( !InitPgm( false, skipPythonInit ) )
166 return false;
167
171 m_bm.Init();
172
173 // Add search paths to feed the PGM_KICAD::SysSearch() function,
174 // currently limited in support to only look for project templates
175 {
176 SEARCH_STACK bases;
177
178 SystemDirsAppend( &bases );
179
180 for( unsigned i = 0; i < bases.GetCount(); ++i )
181 {
182 wxFileName fn( bases[i], wxEmptyString );
183
184 // Add KiCad template file path to search path list.
185 fn.AppendDir( wxT( "template" ) );
186
187 // Only add path if exists and can be read by the user.
188 if( fn.DirExists() && fn.IsDirReadable() )
189 m_bm.m_search.AddPaths( fn.GetPath() );
190 }
191
192 // The versioned TEMPLATE_DIR takes precedence over the search stack template path.
193 if( std::optional<wxString> v = ENV_VAR::GetVersionedEnvVarValue( GetLocalEnvVariables(),
194 wxT( "TEMPLATE_DIR" ) ) )
195 {
196 if( !v->IsEmpty() )
197 m_bm.m_search.Insert( *v, 0 );
198 }
199
200 // We've been adding system (installed default) search paths so far, now for user paths
201 // The default user search path is inside KIPLATFORM::ENV::GetDocumentsPath()
203
204 // ...but the user can override that default with the KICAD_USER_TEMPLATE_DIR env var
205 ENV_VAR_MAP_CITER it = GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
206
207 if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
208 m_bm.m_search.Insert( it->second.GetValue(), 0 );
209 }
210
211 wxFrame* frame = nullptr;
212 KIWAY_PLAYER* playerFrame = nullptr;
213 KICAD_MANAGER_FRAME* managerFrame = nullptr;
214
215 if( appType == KICAD_MAIN_FRAME_T )
216 {
217 managerFrame = new KICAD_MANAGER_FRAME( nullptr, wxT( "KiCad" ), wxDefaultPosition,
218 wxWindow::FromDIP( wxSize( 775, -1 ), NULL ) );
219 frame = managerFrame;
220 }
221 else
222 {
223 // Use KIWAY to create a top window, which registers its existence also.
224 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
225 // and is one of the types in FRAME_T.
226 playerFrame = Kiway.Player( appType, true );
227 frame = playerFrame;
228
229 if( frame == nullptr )
230 {
231 return false;
232 }
233 }
234
235 App().SetTopWindow( frame );
236
237 if( playerFrame )
238 App().SetAppDisplayName( playerFrame->GetAboutTitle() );
239
240 Kiway.SetTop( frame );
241
242 KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
243
244#ifdef KICAD_IPC_API
245 m_api_server = std::make_unique<KICAD_API_SERVER>();
246 m_api_common_handler = std::make_unique<API_HANDLER_COMMON>();
247 m_api_server->RegisterHandler( m_api_common_handler.get() );
248#endif
249
250 wxString projToLoad;
251
252 HideSplash();
253
254 if( playerFrame && parser.GetParamCount() )
255 {
256 // Now after the frame processing, the rest of the positional args are files
257 std::vector<wxString> fileArgs;
258 /*
259 gerbview handles multiple project data files, i.e. gerber files on
260 cmd line. Others currently do not, they handle only one. For common
261 code simplicity we simply pass all the arguments in however, each
262 program module can do with them what they want, ignore, complain
263 whatever. We don't establish policy here, as this is a multi-purpose
264 launcher.
265 */
266
267 for( size_t i = 0; i < parser.GetParamCount(); i++ )
268 fileArgs.push_back( parser.GetParam( i ) );
269
270 // special attention to a single argument: argv[1] (==argSet[0])
271 if( fileArgs.size() == 1 )
272 {
273 wxFileName argv1( fileArgs[0] );
274
275#if defined( PGM_DATA_FILE_EXT )
276 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
277 // it may come from CMake on the compiler command line, but often does not.
278 // This facility is mostly useful for those program footprints
279 // supporting a single argv[1].
280 if( !argv1.GetExt() )
281 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
282#endif
283 argv1.MakeAbsolute();
284
285 fileArgs[0] = argv1.GetFullPath();
286 }
287
288 // Use the KIWAY_PLAYER::OpenProjectFiles() API function:
289 if( !playerFrame->OpenProjectFiles( fileArgs ) )
290 {
291 // OpenProjectFiles() API asks that it report failure to the UI.
292 // Nothing further to say here.
293
294 // We've already initialized things at this point, but wx won't call OnExit if
295 // we fail out. Call our own cleanup routine here to ensure the relevant resources
296 // are freed at the right time (if they aren't, segfaults will occur).
297 OnPgmExit();
298
299 // Fail the process startup if the file could not be opened,
300 // although this is an optional choice, one that can be reversed
301 // also in the KIFACE specific OpenProjectFiles() return value.
302 return false;
303 }
304 }
305 else if( managerFrame )
306 {
307 if( App().argc > 1 )
308 {
309 wxFileName tmp = App().argv[1];
310
311 if( tmp.GetExt() != FILEEXT::ProjectFileExtension
312 && tmp.GetExt() != FILEEXT::LegacyProjectFileExtension )
313 {
314 wxString msg;
315
316 msg.Printf( _( "File '%s'\ndoes not appear to be a valid KiCad project file." ),
317 tmp.GetFullPath() );
318 wxMessageDialog dlg( nullptr, msg, _( "Error" ), wxOK | wxICON_EXCLAMATION );
319 dlg.ShowModal();
320 }
321 else
322 {
323 projToLoad = tmp.GetFullPath();
324 }
325 }
326
327 // If no file was given as an argument, check that there was a file open.
328 if( projToLoad.IsEmpty() && settings->m_OpenProjects.size() )
329 {
330 wxString last_pro = settings->m_OpenProjects.front();
331 settings->m_OpenProjects.erase( settings->m_OpenProjects.begin() );
332
333 if( wxFileExists( last_pro ) )
334 {
335 // Try to open the last opened project,
336 // if a project name is not given when starting Kicad
337 projToLoad = last_pro;
338 }
339 }
340
341 // Do not attempt to load a non-existent project file.
342 if( !projToLoad.empty() )
343 {
344 wxFileName fn( projToLoad );
345
346 if( fn.Exists() )
347 {
348 fn.MakeAbsolute();
349
350 if( appType == KICAD_MAIN_FRAME_T )
351 {
352 managerFrame->LoadProject( fn );
353 }
354 }
355 }
356 }
357
358 frame->Show( true );
359 frame->Raise();
360
361#ifdef KICAD_IPC_API
362 m_api_server->SetReadyToReply();
363#endif
364
365 return true;
366}
367
368
370{
371 return 0;
372}
373
374
376{
378
379#ifdef KICAD_IPC_API
380 m_api_server.reset();
381#endif
382
384 {
386 m_settings_manager->Save();
387 }
388
389 // Destroy everything in PGM_KICAD,
390 // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
391 // than static destruction would.
392 Destroy();
393 git_libgit2_shutdown();
394}
395
396
397void PGM_KICAD::MacOpenFile( const wxString& aFileName )
398{
399#if defined(__WXMAC__)
400
401 KICAD_MANAGER_FRAME* frame = (KICAD_MANAGER_FRAME*) App().GetTopWindow();
402
403 if( !aFileName.empty() && wxFileExists( aFileName ) )
404 frame->LoadProject( wxFileName( aFileName ) );
405
406#endif
407}
408
409
411{
412 // unlike a normal destructor, this is designed to be called more
413 // than once safely:
414
415 m_bm.End();
416
418}
419
420
422
423#ifdef NDEBUG
424// Define a custom assertion handler
425void CustomAssertHandler(const wxString& file,
426 int line,
427 const wxString& func,
428 const wxString& cond,
429 const wxString& msg)
430{
431 Pgm().HandleAssert( file, line, func, cond, msg );
432}
433#endif
434
438struct APP_KICAD : public wxApp
439{
440 APP_KICAD() : wxApp()
441 {
442 SetPgm( &program );
443
444 // Init the environment each platform wants
446 }
447
448
449 bool OnInit() override
450 {
451#ifdef NDEBUG
452 // These checks generate extra assert noise
453 wxSizerFlags::DisableConsistencyChecks();
454 wxDISABLE_DEBUG_SUPPORT();
455 wxSetAssertHandler( CustomAssertHandler );
456#endif
457
458 // Perform platform-specific init tasks
459 if( !KIPLATFORM::APP::Init() )
460 return false;
461
462#ifndef DEBUG
463 // Enable logging traces to the console in release build.
464 // This is usually disabled, but it can be useful for users to run to help
465 // debug issues and other problems.
466 if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
467 {
468 wxLog::EnableLogging( true );
469 wxLog::SetLogLevel( wxLOG_Trace );
470 }
471#endif
472
473 if( !program.OnPgmInit() )
474 {
476 return false;
477 }
478
479 return true;
480 }
481
482 int OnExit() override
483 {
485
486 // Avoid wxLog crashing when used in destructors.
487 wxLog::EnableLogging( false );
488
489 return wxApp::OnExit();
490 }
491
492 int OnRun() override
493 {
494 try
495 {
496 return wxApp::OnRun();
497 }
498 catch(...)
499 {
500 Pgm().HandleException( std::current_exception() );
501 }
502
503 return -1;
504 }
505
506 int FilterEvent( wxEvent& aEvent ) override
507 {
508 if( aEvent.GetEventType() == wxEVT_SHOW )
509 {
510 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
511 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
512
513 std::vector<void*>& dlgs = Pgm().m_ModalDialogs;
514
515 if( dialog )
516 {
517 if( event.IsShown() && dialog->IsModal() )
518 {
519 dlgs.push_back( dialog );
520 }
521 // Under GTK, sometimes the modal flag is cleared before hiding
522 else if( !event.IsShown() && !dlgs.empty() )
523 {
524 // If we close the expected dialog, remove it from our stack
525 if( dlgs.back() == dialog )
526 dlgs.pop_back();
527 // If an out-of-order, remove all dialogs added after the closed one
528 else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog ) ; it != dlgs.end() )
529 dlgs.erase( it, dlgs.end() );
530 }
531 }
532 }
533
534 return Event_Skip;
535 }
536
537#if defined( DEBUG )
541 bool ProcessEvent( wxEvent& aEvent ) override
542 {
543 if( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
544 {
545 wxKeyEvent* keyEvent = static_cast<wxKeyEvent*>( &aEvent );
546
547 if( keyEvent )
548 {
549 wxLogTrace( kicadTraceKeyEvent, "APP_KICAD::ProcessEvent %s", dump( *keyEvent ) );
550 }
551 }
552
553 aEvent.Skip();
554 return false;
555 }
556
564 bool OnExceptionInMainLoop() override
565 {
566 try
567 {
568 throw;
569 }
570 catch(...)
571 {
572 Pgm().HandleException( std::current_exception() );
573 }
574
575 return false; // continue on. Return false to abort program
576 }
577#endif
578
584#if defined( __WXMAC__ )
585 void MacOpenFile( const wxString& aFileName ) override
586 {
587 Pgm().MacOpenFile( aFileName );
588 }
589#endif
590};
591
592IMPLEMENT_APP( APP_KICAD )
593
594
595// The C++ project manager supports one open PROJECT, so Prj() calls within
596// this link image need this function.
598{
599 return Kiway.Prj();
600}
601
const char * name
Definition: DXF_plotter.cpp:57
const wxString & GetAboutTitle() const
The main KiCad project manager frame.
void LoadProject(const wxFileName &aProjectFileName)
std::vector< wxString > m_OpenProjects
A KIFACE implementation.
Definition: kiface_base.h:39
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
virtual bool OpenProjectFiles(const std::vector< wxString > &aFileList, int aCtl=0)
Open a project or set of files given by aFileList.
Definition: kiway_player.h:113
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:284
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:406
void SetCtlBits(int aCtlBits)
Overwrites previously set ctl bits, only for use in kicad.cpp to flip between standalone and manager ...
Definition: kiway.h:417
void OnKiwayEnd()
Definition: kiway.cpp:740
void SetTop(wxFrame *aTop)
Tell this KIWAY about the top most frame in the program and optionally allows it to play the role of ...
Definition: kiway.cpp:88
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:196
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition: paths.cpp:76
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:182
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:924
virtual void MacOpenFile(const wxString &aFileName)=0
Specific to MacOSX (not used under Linux or Windows).
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:408
void Destroy()
Definition: pgm_base.cpp:170
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition: pgm_base.cpp:457
std::vector< void * > m_ModalDialogs
Definition: pgm_base.h:388
void HandleException(std::exception_ptr aPtr)
A exception handler to be used at the top level if exceptions bubble up that for.
Definition: pgm_base.cpp:939
void HandleAssert(const wxString &aFile, int aLine, const wxString &aFunc, const wxString &aCond, const wxString &aMsg)
A common assert handler to be used between single_top and kicad.
Definition: pgm_base.cpp:996
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:142
void HideSplash()
Definition: pgm_base.cpp:446
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:670
PGM_KICAD extends PGM_BASE to bring in FileHistory() and PdfBrowser() which were moved from EDA_APP i...
Definition: pgm_kicad.h:42
bool OnPgmInit()
Definition: kicad.cpp:86
void Destroy()
Definition: kicad.cpp:410
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition: kicad.cpp:397
void OnPgmExit()
Definition: kicad.cpp:375
APP_SETTINGS_BASE * PgmSettings()
Definition: pgm_kicad.h:59
int OnPgmRun()
Definition: kicad.cpp:369
BIN_MOD m_bm
Definition: pgm_kicad.h:72
Container for project specific data.
Definition: project.h:64
Look for files in a number of paths.
Definition: search_stack.h:43
void AddPaths(const wxString &aPaths, int aIndex=-1)
Insert or append path(s).
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
This file is part of the common library.
#define _(s)
Functions related to environment variables, including help functions.
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:33
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
@ FRAME_CALC
Definition: frame_type.h:63
@ FRAME_BM2CMP
Definition: frame_type.h:61
@ FRAME_SCH
Definition: frame_type.h:34
@ FRAME_T_COUNT
Definition: frame_type.h:70
@ FRAME_PL_EDITOR
Definition: frame_type.h:59
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:43
@ FRAME_GERBER
Definition: frame_type.h:57
@ KICAD_MAIN_FRAME_T
Definition: frame_type.h:68
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
PGM_KICAD & PgmTop()
Definition: kicad.cpp:80
PROJECT & Prj()
Definition: kicad.cpp:597
static PGM_KICAD program
Definition: kicad.cpp:78
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition: kicad.cpp:67
KIWAY Kiway(KFCTL_CPP_PROJECT_SUITE)
#define KFCTL_CPP_PROJECT_SUITE
Running under C++ project mgr, possibly with others.
Definition: kiway.h:159
#define KFCTL_STANDALONE
Running as a standalone Top.
Definition: kiway.h:158
This file contains miscellaneous commonly used macros and functions.
KICOMMON_API std::optional< wxString > GetVersionedEnvVarValue(const std::map< wxString, ENV_VAR_ITEM > &aMap, const wxString &aBaseName)
Attempts to retrieve the value of a versioned environment variable, such as KICAD8_TEMPLATE_DIR.
Definition: env_vars.cpp:83
bool Init()
Perform application-specific initialization tasks.
Definition: unix/app.cpp:40
void Init()
Perform environment initialization tasks.
void SetPgm(PGM_BASE *pgm)
Definition: pgm_base.cpp:1072
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
KIWAY Kiway(KFCTL_STANDALONE)
Not publicly visible because most of the action is in PGM_KICAD these days.
Definition: kicad.cpp:439
int OnRun() override
Definition: kicad.cpp:492
APP_KICAD()
Definition: kicad.cpp:440
bool OnInit() override
Definition: kicad.cpp:449
int OnExit() override
Definition: kicad.cpp:482
int FilterEvent(wxEvent &aEvent) override
Definition: kicad.cpp:506
void End()
Definition: bin_mod.cpp:50
void Init()
Definition: bin_mod.cpp:38
SEARCH_STACK m_search
Definition: bin_mod.h:60
void InitSettings(APP_SETTINGS_BASE *aPtr)
Takes ownership of a new application settings object.
Definition: bin_mod.h:53
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Append system places to aSearchStack in a platform specific way and pertinent to KiCad programs.
System directories search utilities.
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.