KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kicad_cli.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 The 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
25
26#include <wx/filename.h>
27#include <wx/log.h>
28#include <wx/stdpaths.h>
29#include <wx/wxcrtvararg.h> //for wxPrintf
30
31#include <kiway.h>
32#include <string_utils.h>
33#include <paths.h>
36#include <systemdirsappend.h>
37#include <trace_helpers.h>
38
39#include <stdexcept>
40
41#include "pgm_kicad.h"
42#include "kicad_manager_frame.h"
43
44#include <build_version.h>
45#include <kiplatform/app.h>
47#include <locale_io.h>
48
49#include "cli/command_jobset.h"
51#include "cli/command_pcb.h"
53#include "cli/command_pcb_drc.h"
74#include "cli/command_fp.h"
78#include "cli/command_sch.h"
79#include "cli/command_sch_erc.h"
82#include "cli/command_sym.h"
86#include "cli/command_version.h"
87#include "cli/exit_codes.h"
88
89// Add this header after all others, to avoid a collision name in a Windows header
90// on mingw.
91#include <wx/app.h>
92
93// a dummy to quiet linking with EDA_BASE_FRAME::config();
94#include <kiface_base.h>
96{
97 // This function should never be called. It is only referenced from
98 // EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
99 // not to be actually called.
100 wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
101
102 throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
103}
104
105
107{
109
110 std::vector<COMMAND_ENTRY> subCommands;
111
112 COMMAND_ENTRY( CLI::COMMAND* aHandler ) : handler( aHandler ){};
113 COMMAND_ENTRY( CLI::COMMAND* aHandler, std::vector<COMMAND_ENTRY> aSub ) :
114 handler( aHandler ), subCommands( aSub ){};
115};
116
169
170
171// clang-format off
172static std::vector<COMMAND_ENTRY> commandStack = {
173 {
174 &jobsetCmd,
175 {
176 {
178 }
179 }
180 },
181 {
182 &fpCmd,
183 {
184 {
186 {
188 }
189 },
190 {
192 }
193 }
194 },
195 {
196 &pcbCmd,
197 {
198 {
199 &pcbDrcCmd
200 },
201 {
203 },
204 {
206 {
230 }
231 },
232 {
234 }
235 }
236 },
237 {
238 &schCmd,
239 {
240 {
241 &schErcCmd
242 },
243 {
245 {
254 }
255 },
256 {
258 }
259 }
260 },
261 {
262 &symCmd,
263 {
264 {
266 {
268 }
269 },
270 {
272 }
273 }
274 },
275 {
276 &versionCmd,
277 }
278};
279// clang-format on
280
281
282static void recurseArgParserBuild( argparse::ArgumentParser& aArgParser, COMMAND_ENTRY& aEntry )
283{
284 aArgParser.add_subparser( aEntry.handler->GetArgParser() );
285
286 for( COMMAND_ENTRY& subEntry : aEntry.subCommands )
287 {
288 recurseArgParserBuild( aEntry.handler->GetArgParser(), subEntry );
289 }
290}
291
292
293static COMMAND_ENTRY* recurseArgParserSubCommandUsed( argparse::ArgumentParser& aArgParser,
294 COMMAND_ENTRY& aEntry )
295{
296 COMMAND_ENTRY* cliCmd = nullptr;
297
298 if( aArgParser.is_subcommand_used( aEntry.handler->GetName() ) )
299 {
300 for( COMMAND_ENTRY& subentry : aEntry.subCommands )
301 {
302 cliCmd = recurseArgParserSubCommandUsed( aEntry.handler->GetArgParser(), subentry );
303 if( cliCmd )
304 break;
305 }
306
307 if(!cliCmd)
308 cliCmd = &aEntry;
309 }
310
311 return cliCmd;
312}
313
314
315static void printHelp( argparse::ArgumentParser& argParser )
316{
317 std::stringstream ss;
318 ss << argParser;
319 wxPrintf( From_UTF8( ss.str().c_str() ) );
320}
321
322
324{
326 App().SetAppDisplayName( wxT( "kicad-cli" ) );
327
328#if defined( DEBUG )
329 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
330
331 if( !wxIsAbsolutePath( absoluteArgv0 ) )
332 {
333 wxLogError( wxT( "No meaningful argv[0]" ) );
334 return false;
335 }
336#endif
337
338 if( !InitPgm( true, true) )
339 return false;
340
341 m_bm.InitSettings( new KICAD_SETTINGS );
344 m_bm.Init();
345
346 return true;
347}
348
349
351{
352 argparse::ArgumentParser argParser( std::string( "kicad-cli" ), GetMajorMinorVersion().ToStdString(),
353 argparse::default_arguments::none );
354
355 argParser.add_argument( "-v", ARG_VERSION )
356 .default_value( false )
357 .help( UTF8STDSTR( _( "prints version information and exits" ) ) )
358 .implicit_value( true )
359 .nargs( 0 );
360
361 argParser.add_argument( ARG_HELP_SHORT, ARG_HELP )
362 .default_value( false )
363 .help( UTF8STDSTR( ARG_HELP_DESC ) )
364 .implicit_value( true )
365 .nargs( 0 );
366
367 for( COMMAND_ENTRY& entry : commandStack )
368 {
369 recurseArgParserBuild( argParser, entry );
370 }
371
372 try
373 {
374 // Use the C locale to parse arguments
375 // Otherwise the decimal separator for the locale will be applied
376 LOCALE_IO dummy;
377 argParser.parse_args( m_argcUtf8, m_argvUtf8 );
378 }
379 // std::runtime_error doesn't seem to be enough for the scan<>()
380 catch( const std::exception& err )
381 {
382 bool requestedHelp = false;
383
384 for( int i = 0; i < m_argcUtf8; ++i )
385 {
386 if( std::string arg( m_argvUtf8[i] ); arg == ARG_HELP_SHORT || arg == ARG_HELP )
387 {
388 requestedHelp = true;
389 break;
390 }
391 }
392
393 if( !requestedHelp )
394 wxPrintf( "%s\n", err.what() );
395
396 // find the correct argparser object to output the command usage info
397 COMMAND_ENTRY* cliCmd = nullptr;
398 for( COMMAND_ENTRY& entry : commandStack )
399 {
400 if( argParser.is_subcommand_used( entry.handler->GetName() ) )
401 {
402 cliCmd = recurseArgParserSubCommandUsed( argParser, entry );
403 }
404 }
405
406 // arg parser uses a stream overload for printing the help
407 // we want to intercept so we can wxString the utf8 contents
408 // because on windows our terminal codepage might not be utf8
409 if( cliCmd )
410 cliCmd->handler->PrintHelp();
411 else
412 {
413 printHelp( argParser );
414 }
415
416 return requestedHelp ? 0 : CLI::EXIT_CODES::ERR_ARGS;
417 }
418
419 if( argParser[ ARG_HELP ] == true )
420 {
421 std::stringstream ss;
422 ss << argParser;
423 wxPrintf( From_UTF8( ss.str().c_str() ) );
424
425 return 0;
426 }
427
428 CLI::COMMAND* cliCmd = nullptr;
429
430 // the version arg gets redirected to the version subcommand
431 if( argParser[ARG_VERSION] == true )
432 {
433 cliCmd = &versionCmd;
434 }
435
436 if( !cliCmd )
437 {
438 for( COMMAND_ENTRY& entry : commandStack )
439 {
440 if( argParser.is_subcommand_used( entry.handler->GetName() ) )
441 {
442 COMMAND_ENTRY* cmdSubEntry = recurseArgParserSubCommandUsed( argParser, entry );
443 if( cmdSubEntry != nullptr )
444 {
445 cliCmd = cmdSubEntry->handler;
446 break;
447 }
448 }
449 }
450 }
451
452 if( cliCmd )
453 {
454 int exitCode = cliCmd->Perform( Kiway );
455
456 if( exitCode != CLI::EXIT_CODES::AVOID_CLOSING )
457 {
458 return exitCode;
459 }
460 else
461 {
462 return 0;
463 }
464 }
465 else
466 {
467 printHelp( argParser );
468
470 }
471}
472
473
475{
477
479 {
481 m_settings_manager->Save();
482 }
483
484 // Destroy everything in PGM_KICAD,
485 // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
486 // than static destruction would.
487 Destroy();
488}
489
490
491void PGM_KICAD::MacOpenFile( const wxString& aFileName )
492{
493#if defined( __WXMAC__ )
494 wxFAIL_MSG( "kicad-cli should not call MacOpenFile" );
495#endif
496}
497
498
500{
501 // unlike a normal destructor, this is designed to be called more
502 // than once safely:
503
504 m_bm.End();
505
507}
508
509
511
513
517struct APP_KICAD_CLI : public wxAppConsole
518{
519 APP_KICAD_CLI() : wxAppConsole()
520 {
521 SetPgm( &program );
522
523 // Init the environment each platform wants
525 }
526
527
528 bool OnInit() override
529 {
530 // Perform platform-specific init tasks
531 if( !KIPLATFORM::APP::Init() )
532 return false;
533
534#ifndef DEBUG
535 // Enable logging traces to the console in release build.
536 // This is usually disabled, but it can be useful for users to run to help
537 // debug issues and other problems.
538 if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
539 {
540 wxLog::EnableLogging( true );
541 wxLog::SetLogLevel( wxLOG_Trace );
542 }
543#endif
544
545 if( !program.OnPgmInit() )
546 {
547 program.OnPgmExit();
548 return false;
549 }
550
551 return true;
552 }
553
554 int OnExit() override
555 {
556 program.OnPgmExit();
557
558#if defined( __FreeBSD__ )
559 // Avoid wxLog crashing when used in destructors.
560 wxLog::EnableLogging( false );
561#endif
562
563 return wxAppConsole::OnExit();
564 }
565
566 int OnRun() override
567 {
568 try
569 {
570 return program.OnPgmRun();
571 }
572 catch( ... )
573 {
574 Pgm().HandleException( std::current_exception() );
575 }
576
577 return -1;
578 }
579
580 int FilterEvent( wxEvent& aEvent ) override
581 {
582 return Event_Skip;
583 }
584
585#if defined( DEBUG )
589 bool ProcessEvent( wxEvent& aEvent ) override
590 {
591 if( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
592 {
593 wxKeyEvent* keyEvent = static_cast<wxKeyEvent*>( &aEvent );
594
595 if( keyEvent )
596 {
597 wxLogTrace( kicadTraceKeyEvent, "APP_KICAD::ProcessEvent %s", dump( *keyEvent ) );
598 }
599 }
600
601 aEvent.Skip();
602 return false;
603 }
604
612 bool OnExceptionInMainLoop() override
613 {
614 try
615 {
616 throw;
617 }
618 catch( ... )
619 {
620 Pgm().HandleException( std::current_exception() );
621 }
622
623 return false; // continue on. Return false to abort program
624 }
625#endif
626};
627
628IMPLEMENT_APP_CONSOLE( APP_KICAD_CLI )
629
630
631// The C++ project manager supports one open PROJECT, so Prj() calls within
632// this link image need this function.
634{
635 return Kiway.Prj();
636}
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
argparse::ArgumentParser & GetArgParser()
Definition command.h:59
const std::string & GetName() const
Definition command.h:60
void PrintHelp()
Definition command.cpp:48
int Perform(KIWAY &aKiway)
Entry point to processing commands from args and doing work.
Definition command.cpp:56
A KIFACE implementation.
Definition kiface_base.h:39
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:286
void OnKiwayEnd()
Definition kiway.cpp:732
virtual wxApp & App()
Return a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition pgm_base.cpp:190
int m_argcUtf8
Definition pgm_base.h:414
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition pgm_base.h:375
void Destroy()
Definition pgm_base.cpp:176
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition pgm_base.cpp:344
char ** m_argvUtf8
argv parameters converted to utf8 form because wxWidgets has opinions.
Definition pgm_base.h:412
void BuildArgvUtf8()
Builds the UTF8 based argv variable.
Definition pgm_base.cpp:299
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:837
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:125
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition pgm_base.cpp:567
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:87
void Destroy()
Definition kicad.cpp:425
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition kicad.cpp:412
void OnPgmExit()
Definition kicad.cpp:388
APP_SETTINGS_BASE * PgmSettings()
Definition pgm_kicad.h:59
int OnPgmRun()
Definition kicad.cpp:382
BIN_MOD m_bm
Definition pgm_kicad.h:72
Container for project specific data.
Definition project.h:65
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Take ownership of the pointer passed in.
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
#define ARG_HELP
Definition command.h:30
#define UTF8STDSTR(s)
Definition command.h:27
#define ARG_HELP_DESC
Definition command.h:32
#define ARG_VERSION
Definition command.h:29
#define ARG_HELP_SHORT
Definition command.h:31
#define _(s)
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
PROJECT & Prj()
Definition kicad.cpp:612
static CLI::PCB_EXPORT_SVG_COMMAND exportPcbSvgCmd
static CLI::SCH_EXPORT_PLOT_COMMAND exportSchHpglCmd
static CLI::SCH_EXPORT_PLOT_COMMAND exportSchSvgCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbVrmlCmd
static CLI::PCB_EXPORT_DXF_COMMAND exportPcbDxfCmd
static CLI::SCH_ERC_COMMAND schErcCmd
static CLI::PCB_EXPORT_HPGL_COMMAND exportPcbHpglCmd
static CLI::PCB_DRC_COMMAND pcbDrcCmd
static CLI::PCB_EXPORT_GERBER_COMMAND exportPcbGerberCmd
static CLI::FP_EXPORT_SVG_COMMAND fpExportSvgCmd
static CLI::PCB_EXPORT_COMMAND exportPcbCmd
static CLI::PCB_RENDER_COMMAND pcbRenderCmd
static CLI::SYM_UPGRADE_COMMAND symUpgradeCmd
static CLI::FP_EXPORT_COMMAND fpExportCmd
static CLI::SCH_EXPORT_PYTHONBOM_COMMAND exportSchPythonBomCmd
static CLI::FP_UPGRADE_COMMAND fpUpgradeCmd
static CLI::SCH_EXPORT_PLOT_COMMAND exportSchPdfCmd
static void printHelp(argparse::ArgumentParser &argParser)
static CLI::JOBSET_RUN_COMMAND jobsetRunCmd
static CLI::PCB_UPGRADE_COMMAND pcbUpgradeCmd
static CLI::PCB_EXPORT_POS_COMMAND exportPcbPosCmd
static CLI::PCB_EXPORT_PS_COMMAND exportPcbPsCmd
static CLI::SYM_COMMAND symCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbStepCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbPlyCmd
static CLI::PCB_EXPORT_GERBERS_COMMAND exportPcbGerbersCmd
static PGM_KICAD program
static CLI::SCH_EXPORT_BOM_COMMAND exportSchBomCmd
static CLI::PCB_EXPORT_IPCD356_COMMAND exportPcbIpcD356Cmd
static CLI::SCH_COMMAND schCmd
static CLI::PCB_COMMAND pcbCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcb3DPDFCmd
static std::vector< COMMAND_ENTRY > commandStack
static CLI::PCB_EXPORT_DRILL_COMMAND exportPcbDrillCmd
static CLI::PCB_EXPORT_IPC2581_COMMAND exportPcbIpc2581Cmd
static CLI::SCH_EXPORT_PLOT_COMMAND exportSchDxfCmd
static CLI::JOBSET_COMMAND jobsetCmd
static CLI::SYM_EXPORT_COMMAND symExportCmd
static CLI::SYM_EXPORT_SVG_COMMAND symExportSvgCmd
static COMMAND_ENTRY * recurseArgParserSubCommandUsed(argparse::ArgumentParser &aArgParser, COMMAND_ENTRY &aEntry)
static CLI::PCB_EXPORT_3D_COMMAND exportPcbU3DCmd
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition kicad_cli.cpp:95
static CLI::PCB_EXPORT_ODB_COMMAND exportPcbOdbCmd
static CLI::VERSION_COMMAND versionCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbStlCmd
static CLI::PCB_EXPORT_PDF_COMMAND exportPcbPdfCmd
static CLI::SCH_UPGRADE_COMMAND schUpgradeCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbXaoCmd
static void recurseArgParserBuild(argparse::ArgumentParser &aArgParser, COMMAND_ENTRY &aEntry)
static CLI::SCH_EXPORT_NETLIST_COMMAND exportSchNetlistCmd
static CLI::SCH_EXPORT_PLOT_COMMAND exportSchPostscriptCmd
static CLI::PCB_EXPORT_GENCAD_COMMAND exportPcbGencadCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbStepzCmd
static CLI::FP_COMMAND fpCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbGlbCmd
static CLI::SCH_EXPORT_COMMAND exportSchCmd
static CLI::PCB_EXPORT_3D_COMMAND exportPcbBrepCmd
#define KFCTL_CPP_PROJECT_SUITE
Running under C++ project mgr, possibly with others.
Definition kiway.h:161
#define KFCTL_CLI
Running as CLI app.
Definition kiway.h:162
static const int ERR_ARGS
Definition exit_codes.h:31
static const int AVOID_CLOSING
Definition exit_codes.h:28
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:927
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:913
PGM_SINGLE_TOP program
KIWAY Kiway(KFCTL_STANDALONE)
std::vector< FAB_LAYER_COLOR > dummy
wxString From_UTF8(const char *cstring)
Not publicly visible because most of the action is in PGM_KICAD these days.
int OnExit() override
bool OnInit() override
int FilterEvent(wxEvent &aEvent) override
int OnRun() override
COMMAND_ENTRY(CLI::COMMAND *aHandler)
COMMAND_ENTRY(CLI::COMMAND *aHandler, std::vector< COMMAND_ENTRY > aSub)
CLI::COMMAND * handler
std::vector< COMMAND_ENTRY > subCommands
System directories search utilities.
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.